{"kind":"AgentDefinition","metadata":{"namespace":"community","name":"power-bi-custom-visuals-development","version":"0.1.0"},"spec":{"agents_md":"---\ndescription: 'Comprehensive Power BI custom visuals development guide covering React, D3.js integration, TypeScript patterns, testing frameworks, and advanced visualization techniques.'\napplyTo: '**/*.{ts,tsx,js,jsx,json,less,css}'\n---\n\n# Power BI Custom Visuals Development Best Practices\n\n## Overview\nThis document provides comprehensive instructions for developing custom Power BI visuals using modern web technologies including React, D3.js, TypeScript, and advanced testing frameworks, based on Microsoft's official guidance and community best practices.\n\n## Development Environment Setup\n\n### 1. Project Initialization\n```typescript\n// Install Power BI visuals tools globally\nnpm install -g powerbi-visuals-tools\n\n// Create new visual project\npbiviz new MyCustomVisual\ncd MyCustomVisual\n\n// Start development server\npbiviz start\n```\n\n### 2. TypeScript Configuration\n```json\n{\n    \"compilerOptions\": {\n        \"jsx\": \"react\",\n        \"types\": [\"react\", \"react-dom\"],\n        \"allowJs\": false,\n        \"emitDecoratorMetadata\": true,\n        \"experimentalDecorators\": true,\n        \"target\": \"es6\",\n        \"sourceMap\": true,\n        \"outDir\": \"./.tmp/build/\",\n        \"moduleResolution\": \"node\",\n        \"declaration\": true,\n        \"lib\": [\n            \"es2015\",\n            \"dom\"\n        ]\n    },\n    \"files\": [\n        \"./src/visual.ts\"\n    ]\n}\n```\n\n## Core Visual Development Patterns\n\n### 1. Basic Visual Structure\n```typescript\n\"use strict\";\nimport powerbi from \"powerbi-visuals-api\";\n\nimport DataView = powerbi.DataView;\nimport VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;\nimport VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;\nimport IVisual = powerbi.extensibility.visual.IVisual;\nimport IVisualHost = powerbi.extensibility.IVisualHost;\n\nimport \"./../style/visual.less\";\n\nexport class Visual implements IVisual {\n    private target: HTMLElement;\n    private host: IVisualHost;\n\n    constructor(options: VisualConstructorOptions) {\n        this.target = options.element;\n        this.host = options.host;\n    }\n\n    public update(options: VisualUpdateOptions) {\n        const dataView: DataView = options.dataViews[0];\n        \n        if (!dataView) {\n            return;\n        }\n\n        // Visual update logic here\n    }\n\n    public getFormattingModel(): powerbi.visuals.FormattingModel {\n        return this.formattingSettingsService.buildFormattingModel(this.formattingSettings);\n    }\n}\n```\n\n### 2. Data View Processing\n```typescript\n// Single data mapping example\nexport class Visual implements IVisual {\n    private valueText: HTMLParagraphElement;\n\n    constructor(options: VisualConstructorOptions) {\n        this.target = options.element;\n        this.host = options.host;\n        this.valueText = document.createElement(\"p\");\n        this.target.appendChild(this.valueText);\n    }\n\n    public update(options: VisualUpdateOptions) {\n        const dataView: DataView = options.dataViews[0];\n        const singleDataView: DataViewSingle = dataView.single;\n\n        if (!singleDataView || !singleDataView.value ) {\n            return;\n        }\n\n        this.valueText.innerText = singleDataView.value.toString();\n    }\n}\n```\n\n## React Integration\n\n### 1. React Visual Setup\n```typescript\nimport * as React from \"react\";\nimport * as ReactDOM from \"react-dom\";\nimport ReactCircleCard from \"./component\";\n\nexport class Visual implements IVisual {\n    private target: HTMLElement;\n    private reactRoot: React.ComponentElement\u003cany, any\u003e;\n\n    constructor(options: VisualConstructorOptions) {\n        this.reactRoot = React.createElement(ReactCircleCard, {});\n        this.target = options.element;\n\n        ReactDOM.render(this.reactRoot, this.target);\n    }\n\n    public update(options: VisualUpdateOptions) {\n        const dataView: DataView = options.dataViews[0];\n        \n        if (dataView) {\n            const reactProps = this.parseDataView(dataView);\n            this.reactRoot = React.createElement(ReactCircleCard, reactProps);\n            ReactDOM.render(this.reactRoot, this.target);\n        }\n    }\n\n    private parseDataView(dataView: DataView): any {\n        // Transform Power BI data for React component\n        return {\n            data: dataView.categorical?.values?.[0]?.values || [],\n            categories: dataView.categorical?.categories?.[0]?.values || []\n        };\n    }\n}\n```\n\n### 2. React Component with Props\n```typescript\n// React component for Power BI visual\nimport * as React from \"react\";\n\nexport interface ReactCircleCardProps {\n    data: number[];\n    categories: string[];\n    size?: number;\n    color?: string;\n}\n\nexport const ReactCircleCard: React.FC\u003cReactCircleCardProps\u003e = (props) =\u003e {\n    const { data, categories, size = 200, color = \"#3498db\" } = props;\n    \n    const maxValue = Math.max(...data);\n    const minValue = Math.min(...data);\n    \n    return (\n        \u003cdiv className=\"react-circle-card\"\u003e\n            {data.map((value, index) =\u003e {\n                const radius = ((value - minValue) / (maxValue - minValue)) * size / 2;\n                return (\n                    \u003cdiv key={index} className=\"data-point\"\u003e\n                        \u003cdiv \n                            className=\"circle\"\n                            style={{\n                                width: radius * 2,\n                                height: radius * 2,\n                                backgroundColor: color,\n                                borderRadius: '50%'\n                            }}\n                        /\u003e\n                        \u003cspan className=\"label\"\u003e{categories[index]}: {value}\u003c/span\u003e\n                    \u003c/div\u003e\n                );\n            })}\n        \u003c/div\u003e\n    );\n};\n\nexport default ReactCircleCard;\n```\n\n## D3.js Integration\n\n### 1. D3 with TypeScript\n```typescript\nimport * as d3 from \"d3\";\ntype Selection\u003cT extends d3.BaseType\u003e = d3.Selection\u003cT, any, any, any\u003e;\n\nexport class Visual implements IVisual {\n    private svg: Selection\u003cSVGElement\u003e;\n    private container: Selection\u003cSVGElement\u003e;\n    private host: IVisualHost;\n\n    constructor(options: VisualConstructorOptions) {\n        this.host = options.host;\n        this.svg = d3.select(options.element)\n            .append('svg')\n            .classed('visual-svg', true);\n        \n        this.container = this.svg\n            .append('g')\n            .classed('visual-container', true);\n    }\n\n    public update(options: VisualUpdateOptions) {\n        const dataView = options.dataViews[0];\n        \n        if (!dataView) {\n            return;\n        }\n\n        const width = options.viewport.width;\n        const height = options.viewport.height;\n        \n        this.svg\n            .attr('width', width)\n            .attr('height', height);\n\n        // D3 data binding and visualization logic\n        this.renderChart(dataView, width, height);\n    }\n\n    private renderChart(dataView: DataView, width: number, height: number): void {\n        const data = this.transformData(dataView);\n        \n        // Create scales\n        const xScale = d3.scaleBand()\n            .domain(data.map(d =\u003e d.category))\n            .range([0, width])\n            .padding(0.1);\n\n        const yScale = d3.scaleLinear()\n            .domain([0, d3.max(data, d =\u003e d.value)])\n            .range([height, 0]);\n\n        // Bind data and create bars\n        const bars = this.container.selectAll('.bar')\n            .data(data);\n\n        bars.enter()\n            .append('rect')\n            .classed('bar', true)\n            .merge(bars)\n            .attr('x', d =\u003e xScale(d.category))\n            .attr('y', d =\u003e yScale(d.value))\n            .attr('width', xScale.bandwidth())\n            .attr('height', d =\u003e height - yScale(d.value))\n            .style('fill', '#3498db');\n\n        bars.exit().remove();\n    }\n\n    private transformData(dataView: DataView): any[] {\n        // Transform Power BI DataView to D3-friendly format\n        const categorical = dataView.categorical;\n        const categories = categorical.categories[0];\n        const values = categorical.values[0];\n\n        return categories.values.map((category, index) =\u003e ({\n            category: category.toString(),\n            value: values.values[index] as number\n        }));\n    }\n}\n```\n\n### 2. Advanced D3 Patterns\n```typescript\n// Complex D3 visualization with interactions\nexport class AdvancedD3Visual implements IVisual {\n    private svg: Selection\u003cSVGElement\u003e;\n    private tooltip: Selection\u003cHTMLDivElement\u003e;\n    private selectionManager: ISelectionManager;\n\n    constructor(options: VisualConstructorOptions) {\n        this.host = options.host;\n        this.selectionManager = this.host.createSelectionManager();\n        \n        // Create main SVG\n        this.svg = d3.select(options.element)\n            .append('svg');\n        \n        // Create tooltip\n        this.tooltip = d3.select(options.element)\n            .append('div')\n            .classed('tooltip', true)\n            .style('opacity', 0);\n    }\n\n    private createInteractiveElements(data: VisualDataPoint[]): void {\n        const circles = this.svg.selectAll('.data-circle')\n            .data(data);\n\n        const circlesEnter = circles.enter()\n            .append('circle')\n            .classed('data-circle', true);\n\n        circlesEnter.merge(circles)\n            .attr('cx', d =\u003e d.x)\n            .attr('cy', d =\u003e d.y)\n            .attr('r', d =\u003e d.radius)\n            .style('fill', d =\u003e d.color)\n            .style('stroke', d =\u003e d.strokeColor)\n            .style('stroke-width', d =\u003e `${d.strokeWidth}px`)\n            .on('click', (event, d) =\u003e {\n                // Handle selection\n                this.selectionManager.select(d.selectionId, event.ctrlKey);\n            })\n            .on('mouseover', (event, d) =\u003e {\n                // Show tooltip\n                this.tooltip\n                    .style('opacity', 1)\n                    .style('left', (event.pageX + 10) + 'px')\n                    .style('top', (event.pageY - 10) + 'px')\n                    .html(`${d.category}: ${d.value}`);\n            })\n            .on('mouseout', () =\u003e {\n                // Hide tooltip\n                this.tooltip.style('opacity', 0);\n            });\n\n        circles.exit().remove();\n    }\n}\n```\n\n## Advanced Visual Features\n\n### 1. Custom Formatting Model\n```typescript\nimport { formattingSettings } from \"powerbi-visuals-utils-formattingmodel\";\n\nexport class VisualFormattingSettingsModel extends formattingSettings.CompositeFormattingSettingsModel {\n    // Color settings card\n    public colorCard: ColorCardSettings = new ColorCardSettings();\n    \n    // Data point settings card  \n    public dataPointCard: DataPointCardSettings = new DataPointCardSettings();\n    \n    // General settings card\n    public generalCard: GeneralCardSettings = new GeneralCardSettings();\n\n    public cards: formattingSettings.SimpleCard[] = [this.colorCard, this.dataPointCard, this.generalCard];\n}\n\nexport class ColorCardSettings extends formattingSettings.SimpleCard {\n    name: string = \"colorCard\";\n    displayName: string = \"Color\";\n\n    public defaultColor: formattingSettings.ColorPicker = new formattingSettings.ColorPicker({\n        name: \"defaultColor\",\n        displayName: \"Default color\",\n        value: { value: \"#3498db\" }\n    });\n\n    public showAllDataPoints: formattingSettings.ToggleSwitch = new formattingSettings.ToggleSwitch({\n        name: \"showAllDataPoints\",\n        displayName: \"Show all\",\n        value: false\n    });\n}\n```\n\n### 2. Interactivity and Selections\n```typescript\nimport { interactivitySelectionService, baseBehavior } from \"powerbi-visuals-utils-interactivityutils\";\n\nexport interface VisualDataPoint extends interactivitySelectionService.SelectableDataPoint {\n    value: powerbi.PrimitiveValue;\n    category: string;\n    color: string;\n    selectionId: ISelectionId;\n}\n\nexport class VisualBehavior extends baseBehavior.BaseBehavior\u003cVisualDataPoint\u003e {\n    protected bindClick() {\n        // Implement click behavior for data point selection\n        this.behaviorOptions.clearCatcher.on('click', () =\u003e {\n            this.selectionHandler.handleClearSelection();\n        });\n\n        this.behaviorOptions.elementsSelection.on('click', (event, dataPoint) =\u003e {\n            event.stopPropagation();\n            this.selectionHandler.handleSelection(dataPoint, event.ctrlKey);\n        });\n    }\n\n    protected bindContextMenu() {\n        // Implement context menu behavior\n        this.behaviorOptions.elementsSelection.on('contextmenu', (event, dataPoint) =\u003e {\n            this.selectionHandler.handleContextMenu(\n                dataPoint ? dataPoint.selectionId : null,\n                {\n                    x: event.clientX,\n                    y: event.clientY\n                }\n            );\n            event.preventDefault();\n        });\n    }\n}\n```\n\n### 3. Landing Page Implementation\n```typescript\nexport class Visual implements IVisual {\n    private element: HTMLElement;\n    private isLandingPageOn: boolean;\n    private LandingPageRemoved: boolean;\n    private LandingPage: d3.Selection\u003cany\u003e;\n\n    constructor(options: VisualConstructorOptions) {\n        this.element = options.element;\n    }\n\n    public update(options: VisualUpdateOptions) {\n        this.HandleLandingPage(options);\n    }\n\n    private HandleLandingPage(options: VisualUpdateOptions) {\n        if(!options.dataViews || !options.dataViews[0]?.metadata?.columns?.length){\n            if(!this.isLandingPageOn) {\n                this.isLandingPageOn = true;\n                const SampleLandingPage: Element = this.createSampleLandingPage();\n                this.element.appendChild(SampleLandingPage);\n                this.LandingPage = d3.select(SampleLandingPage);\n            }\n        } else {\n            if(this.isLandingPageOn \u0026\u0026 !this.LandingPageRemoved){\n                this.LandingPageRemoved = true;\n                this.LandingPage.remove();\n            }\n        }\n    }\n\n    private createSampleLandingPage(): Element {\n        const landingPage = document.createElement(\"div\");\n        landingPage.className = \"landing-page\";\n        landingPage.innerHTML = `\n            \u003cdiv class=\"landing-page-content\"\u003e\n                \u003ch2\u003eCustom Visual\u003c/h2\u003e\n                \u003cp\u003eAdd data to get started\u003c/p\u003e\n                \u003cdiv class=\"landing-page-icon\"\u003e📊\u003c/div\u003e\n            \u003c/div\u003e\n        `;\n        return landingPage;\n    }\n}\n```\n\n## Testing Framework\n\n### 1. Unit Testing Setup\n```typescript\n// Webpack configuration for testing\nconst path = require('path');\nconst webpack = require(\"webpack\");\n\nmodule.exports = {\n    devtool: 'source-map',\n    mode: 'development',\n    module: {\n        rules: [\n            {\n                test: /\\.tsx?$/,\n                use: 'ts-loader',\n                exclude: /node_modules/\n            },\n            {\n                test: /\\.json$/,\n                loader: 'json-loader'\n            },\n            {\n                test: /\\.tsx?$/i,\n                enforce: 'post',\n                include: path.resolve(__dirname, 'src'),\n                exclude: /(node_modules|resources\\/js\\/vendor)/,\n                loader: 'coverage-istanbul-loader',\n                options: { esModules: true }\n            }\n        ]\n    },\n    externals: {\n        \"powerbi-visuals-api\": '{}'\n    },\n    resolve: {\n        extensions: ['.tsx', '.ts', '.js', '.css']\n    },\n    output: {\n        path: path.resolve(__dirname, \".tmp/test\")\n    },\n    plugins: [\n        new webpack.ProvidePlugin({\n            'powerbi-visuals-api': null\n        })\n    ]\n};\n```\n\n### 2. Visual Testing Utilities\n```typescript\n// Test utilities for Power BI visuals\nexport class VisualTestUtils {\n    public static d3Click(element: JQuery, x: number, y: number): void {\n        const event = new MouseEvent('click', {\n            clientX: x,\n            clientY: y,\n            button: 0\n        });\n        element[0].dispatchEvent(event);\n    }\n\n    public static d3KeyEvent(element: JQuery, typeArg: string, keyArg: string, keyCode: number): void {\n        const event = new KeyboardEvent(typeArg, {\n            key: keyArg,\n            code: keyArg,\n            keyCode: keyCode\n        });\n        element[0].dispatchEvent(event);\n    }\n\n    public static createVisualHost(): IVisualHost {\n        return {\n            createSelectionIdBuilder: () =\u003e new SelectionIdBuilder(),\n            createSelectionManager: () =\u003e new SelectionManager(),\n            colorPalette: new ColorPalette(),\n            eventService: new EventService(),\n            tooltipService: new TooltipService()\n        } as IVisualHost;\n    }\n\n    public static createUpdateOptions(dataView: DataView, viewport?: IViewport): VisualUpdateOptions {\n        return {\n            dataViews: [dataView],\n            viewport: viewport || { width: 500, height: 500 },\n            operationKind: VisualDataChangeOperationKind.Create,\n            type: VisualUpdateType.Data\n        };\n    }\n}\n```\n\n### 3. Component Testing\n```typescript\n// Jest test for React component\nimport * as React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport '@testing-library/jest-dom';\nimport ReactCircleCard from '../src/component';\n\ndescribe('ReactCircleCard', () =\u003e {\n    const mockProps = {\n        data: [10, 20, 30],\n        categories: ['A', 'B', 'C'],\n        size: 200,\n        color: '#3498db'\n    };\n\n    test('renders with correct data points', () =\u003e {\n        render(\u003cReactCircleCard {...mockProps} /\u003e);\n        \n        expect(screen.getByText('A: 10')).toBeInTheDocument();\n        expect(screen.getByText('B: 20')).toBeInTheDocument();\n        expect(screen.getByText('C: 30')).toBeInTheDocument();\n    });\n\n    test('applies correct styling', () =\u003e {\n        render(\u003cReactCircleCard {...mockProps} /\u003e);\n        \n        const circles = document.querySelectorAll('.circle');\n        expect(circles).toHaveLength(3);\n        \n        circles.forEach(circle =\u003e {\n            expect(circle).toHaveStyle('backgroundColor: #3498db');\n            expect(circle).toHaveStyle('borderRadius: 50%');\n        });\n    });\n\n    test('handles empty data gracefully', () =\u003e {\n        const emptyProps = { ...mockProps, data: [], categories: [] };\n        const { container } = render(\u003cReactCircleCard {...emptyProps} /\u003e);\n        \n        expect(container.querySelector('.data-point')).toBeNull();\n    });\n});\n```\n\n## Advanced Patterns\n\n### 1. Dialog Box Implementation\n```typescript\nimport DialogConstructorOptions = powerbi.extensibility.visual.DialogConstructorOptions;\nimport DialogAction = powerbi.DialogAction;\nimport * as ReactDOM from 'react-dom';\nimport * as React from 'react';\n\nexport class CustomDialog {\n    private dialogContainer: HTMLElement;\n\n    constructor(options: DialogConstructorOptions) {\n        this.dialogContainer = options.element;\n        this.initializeDialog();\n    }\n\n    private initializeDialog(): void {\n        const dialogContent = React.createElement(DialogContent, {\n            onSave: this.handleSave.bind(this),\n            onCancel: this.handleCancel.bind(this)\n        });\n\n        ReactDOM.render(dialogContent, this.dialogContainer);\n    }\n\n    private handleSave(data: any): void {\n        // Process save action\n        this.closeDialog(DialogAction.Save, data);\n    }\n\n    private handleCancel(): void {\n        // Process cancel action\n        this.closeDialog(DialogAction.Cancel);\n    }\n\n    private closeDialog(action: DialogAction, data?: any): void {\n        // Close dialog with action and optional data\n        powerbi.extensibility.visual.DialogUtils.closeDialog(action, data);\n    }\n}\n```\n\n### 2. Conditional Formatting Integration\n```typescript\nimport powerbiVisualsApi from \"powerbi-visuals-api\";\nimport { ColorHelper } from \"powerbi-visuals-utils-colorutils\";\n\nexport class Visual implements IVisual {\n    private colorHelper: ColorHelper;\n\n    constructor(options: VisualConstructorOptions) {\n        this.colorHelper = new ColorHelper(\n            options.host.colorPalette,\n            { objectName: \"dataPoint\", propertyName: \"fill\" },\n            \"#3498db\"  // Default color\n        );\n    }\n\n    private applyConditionalFormatting(dataPoints: VisualDataPoint[]): VisualDataPoint[] {\n        return dataPoints.map(dataPoint =\u003e {\n            // Get conditional formatting color\n            const color = this.colorHelper.getColorForDataPoint(dataPoint.dataViewObject);\n            \n            return {\n                ...dataPoint,\n                color: color,\n                strokeColor: this.darkenColor(color, 0.2),\n                strokeWidth: 2\n            };\n        });\n    }\n\n    private darkenColor(color: string, amount: number): string {\n        // Utility function to darken a color for stroke\n        const colorObj = d3.color(color);\n        return colorObj ? colorObj.darker(amount).toString() : color;\n    }\n}\n```\n\n### 3. Tooltip Integration\n```typescript\nimport { createTooltipServiceWrapper, TooltipEventArgs, ITooltipServiceWrapper } from \"powerbi-visuals-utils-tooltiputils\";\n\nexport class Visual implements IVisual {\n    private tooltipServiceWrapper: ITooltipServiceWrapper;\n\n    constructor(options: VisualConstructorOptions) {\n        this.tooltipServiceWrapper = createTooltipServiceWrapper(\n            options.host.tooltipService,\n            options.element\n        );\n    }\n\n    private addTooltips(selection: d3.Selection\u003cany, VisualDataPoint, any, any\u003e): void {\n        this.tooltipServiceWrapper.addTooltip(\n            selection,\n            (tooltipEvent: TooltipEventArgs\u003cVisualDataPoint\u003e) =\u003e {\n                const dataPoint = tooltipEvent.data;\n                return [\n                    {\n                        displayName: \"Category\",\n                        value: dataPoint.category\n                    },\n                    {\n                        displayName: \"Value\", \n                        value: dataPoint.value.toString()\n                    },\n                    {\n                        displayName: \"Percentage\",\n                        value: `${((dataPoint.value / this.totalValue) * 100).toFixed(1)}%`\n                    }\n                ];\n            }\n        );\n    }\n}\n```\n\n## Performance Optimization\n\n### 1. Data Reduction Strategies\n```json\n// Visual capabilities with data reduction\n\"dataViewMappings\": {\n    \"categorical\": {\n        \"categories\": {\n            \"for\": { \"in\": \"category\" },\n            \"dataReductionAlgorithm\": {\n                \"window\": {\n                    \"count\": 300\n                }\n            }  \n        },\n        \"values\": {\n            \"group\": {\n                \"by\": \"series\",\n                \"select\": [{\n                    \"for\": {\n                        \"in\": \"measure\"\n                    }\n                }],\n                \"dataReductionAlgorithm\": {\n                    \"top\": {\n                        \"count\": 100\n                    }\n                }  \n            }\n        }\n    }\n}\n```\n\n### 2. Efficient Rendering Patterns\n```typescript\nexport class OptimizedVisual implements IVisual {\n    private animationFrameId: number;\n    private renderQueue: (() =\u003e void)[] = [];\n\n    public update(options: VisualUpdateOptions) {\n        // Queue render operation instead of immediate execution\n        this.queueRender(() =\u003e this.performUpdate(options));\n    }\n\n    private queueRender(renderFunction: () =\u003e void): void {\n        this.renderQueue.push(renderFunction);\n        \n        if (!this.animationFrameId) {\n            this.animationFrameId = requestAnimationFrame(() =\u003e {\n                this.processRenderQueue();\n            });\n        }\n    }\n\n    private processRenderQueue(): void {\n        // Process all queued render operations\n        while (this.renderQueue.length \u003e 0) {\n            const renderFunction = this.renderQueue.shift();\n            if (renderFunction) {\n                renderFunction();\n            }\n        }\n        \n        this.animationFrameId = null;\n    }\n\n    private performUpdate(options: VisualUpdateOptions): void {\n        // Use virtual DOM or efficient diffing strategies\n        const currentData = this.transformData(options.dataViews[0]);\n        \n        if (this.hasDataChanged(currentData)) {\n            this.renderVisualization(currentData);\n            this.previousData = currentData;\n        }\n    }\n\n    private hasDataChanged(newData: any[]): boolean {\n        // Efficient data comparison\n        return JSON.stringify(newData) !== JSON.stringify(this.previousData);\n    }\n}\n```\n\nRemember: Custom visual development requires understanding both Power BI's visual framework and modern web development practices. Focus on creating reusable, testable, and performant visualizations that enhance the Power BI ecosystem.","description":"Comprehensive Power BI custom visuals development guide covering React, D3.js integration, TypeScript patterns, testing frameworks, and advanced visualization techniques.","import":{"commit_sha":"541b7819d8c3545c6df122491af4fa1eae415779","imported_at":"2026-05-18T20:05:35Z","license_text":"MIT License\n\nCopyright GitHub, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","owner":"github","repo":"github/awesome-copilot","source_url":"https://github.com/github/awesome-copilot/blob/541b7819d8c3545c6df122491af4fa1eae415779/instructions/power-bi-custom-visuals-development.instructions.md"},"manifest":{}},"content_hash":[35,87,234,178,201,39,165,123,15,15,209,137,214,64,129,64,79,77,173,81,108,181,115,23,189,96,186,43,103,0,103,29],"trust_level":"unsigned","yanked":false}
