Animated Ability Chart

Size
4,994 Kb
Views
32,384

How do I make an animated ability chart?

Designed by using D3.js. What is a animated ability chart? How do you make a animated ability chart? This script and codes were developed by AaronChuo (小狂) on 11 September 2022, Sunday.

Animated Ability Chart Previews

Animated Ability Chart - Script Codes HTML Codes

<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>Animated Ability Chart</title> <meta property="og:image" content="https://lh6.googleusercontent.com/-tx6wuZpEER9Z5VGhv9bzHOatKnhDr0pYf-KenQwrGaM2fDgubdOUvRfiuOjyZGOhykXrjm2IRvSRxc=w2560-h1670" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css"> <link rel="stylesheet" href="css/style.css">
</head>
<body> <div id="container"></div> <script src='https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js'></script> <script src="js/index.js"></script>
</body>
</html>

Animated Ability Chart - Script Codes CSS Codes

.group { cursor: pointer;
}
.outer-line { fill: transparent; stroke: #999; stroke-width: 1px;
}
.inner-line { stroke: #999; stroke-width: 1px; -webkit-transition: stroke 200ms ease; transition: stroke 200ms ease;
}
.group:hover .inner-line { stroke: #666;
}
.chain-line { stroke: #9CF; stroke-width: 1px;
}
.data-area { fill: #9CF; opacity: 0;
}
.data-point { fill: #F9C; opacity: 0; -webkit-transition: opacity 200ms ease; transition: opacity 200ms ease;
}
.group:hover .data-point { opacity: 1;
}
.label { fill: #999; text-anchor: middle; font-size: 1.5em; opacity: 0; -webkit-transition: fill, font-size 200ms ease; transition: fill, font-size 200ms ease;
}
.group:hover .label { fill: #F9C; font-size: 1.8em;
}
.value-label { fill: #8AF; text-anchor: middle; font-size: 1.6em; opacity: 0; -webkit-transition: fill, font-size 200ms ease; transition: fill, font-size 200ms ease;
}
.group:hover .value-label { fill: #F9C; font-size: 1.9em;
}
.warning { fill: #C66; text-anchor: middle;
}

Animated Ability Chart - Script Codes JS Codes

(function(d3) { 'use strict'; // 資料 // 資料至少需3筆以上 // updated: 未達3筆則不產圖表,改為提示訊息 // updated: 將value限制在0 ~ maxValue之間,避免不正常繪製而產生的錯誤 var dataset = [ {name: '智慧', value: 9}, {name: '魅力', value: 7}, {name: '熱情', value: 8}, {name: '敏銳', value: 6}, {name: '責任', value: 7}, {name: '耐心', value: 3} ]; var WIDTH = window.innerWidth, HEIGHT = window.innerHeight; var vis, sides, maxValue = 10, radius = Math.min(WIDTH, HEIGHT) / 4, center = {x: WIDTH / 2, y: HEIGHT / 2}; var init = function() { sides = dataset.length; if(sides < 3) { warning('資料至少要3筆以上'); return false; } setPoints(); chartBuilding(); chartStyling(); }; // 建置圖形結構 var chartBuilding = function() { vis = d3.select('#container') .append('svg:svg') .attr('class', 'ability-chart') .append('svg:g') .attr('class', 'vis'); vis.append('svg:text') .attr('class', 'heading'); vis.append('svg:path') .attr('id', 'outer-line') .attr('class', 'outer-line'); vis.append('svg:path') .attr('id', 'data-area') .attr('class', 'data-area'); vis.selectAll('g') .data(dataset) .enter() .append('svg:g') .attr('class', 'group'); vis.selectAll('.group') .append('line') .attr('class', 'inner-line'); vis.selectAll('.group') .append('line') .attr('class', 'chain-line'); vis.selectAll('.group') .append('svg:circle') .attr('class', 'data-point'); vis.selectAll('.group') .append('svg:text') .attr('class', 'label') .text(function(d) { return d.name || '未命名'; }); vis.selectAll('.group') .append('svg:text') .attr('class', 'value-label') .text(function(d) { return (d.value || 0) > maxValue ? maxValue : (d.value < 0 ? 0 : d.value); }); }; // 設定圖形外觀 var chartStyling = function() { d3.select('body') .style('font-size', radius * 0.1 + 'px'); d3.select('.ability-chart') .attr('width', WIDTH) .attr('height', HEIGHT); d3.selectAll('.label') .attr('transform', function(d) { return 'translate(' + d.label.x + ',' + d.label.y + ')'; }) .attr('dy', radius * 0.07); d3.selectAll('.value-label') .attr('transform', function(d) { return 'translate(' + d.valueLabel.x + ',' + d.valueLabel.y + ')'; }) .attr('dy', radius * 0.07); d3.selectAll('.data-point') .attr('cx', function(d) { return d.dataPoint.x; }) .attr('cy', function(d) { return d.dataPoint.y; }) .attr('r', radius * 0.03); drawOuterLine(); drawInnerLine(); drawChainLine(); drawDataArea(); showLabel(); showValue(); }; // 計算各頂點座標、資料點座標、名稱座標 (參考國中數學) var setPoints = function() { var angle, percent, r, s, currentValue, base = {}, vertex = {}, label = {}, valueLabel = {}, dataPoint = {}; for(var i = 0; i < sides; i++) { angle = (2 * Math.PI / sides * i) + (-Math.PI / 2); base.x = radius * Math.cos(angle); base.y = radius * Math.sin(angle); vertex.x = base.x + center.x; vertex.y = base.y + center.y; label.x = base.x * 1.4 + center.x; label.y = base.y * 1.4 + center.y; valueLabel.x = base.x * 1.12 + center.x; valueLabel.y = base.y * 1.12 + center.y; currentValue = dataset[i].value; currentValue = currentValue > maxValue ? maxValue : (currentValue < 0 ? 0 : currentValue); percent = currentValue / maxValue; r = radius * percent, s = radius - r; dataPoint.x = (r * vertex.x + s * center.x) / radius; dataPoint.y = (r * vertex.y + s * center.y) / radius; dataset[i].vertex = {x: vertex.x, y: vertex.y}; dataset[i].label = {x: label.x, y: label.y}; dataset[i].valueLabel = {x: valueLabel.x, y: valueLabel.y}; dataset[i].dataPoint = {x: dataPoint.x, y: dataPoint.y}; } }; // 取得外邊線的路徑 var getOuterLinePath = function() { var path; for(var i = 0; i < dataset.length; i++) { if(i === 0) { path = 'M '; } else { path += ' L '; } path += dataset[i].vertex.x + ' ' + dataset[i].vertex.y; } path += ' Z'; return path; }; // 取得由所有資料點座標連起來的資料區域路徑 var getDataAreaPath = function() { var path; for(var i = 0; i < dataset.length; i++) { if(i === 0) { path = 'M '; } else { path += ' L '; } path += dataset[i].dataPoint.x + ' ' + dataset[i].dataPoint.y; } path += ' Z'; return path; }; // 外邊線的繪製效果 var drawOuterLine = function() { d3.select('.outer-line') .attr('d', getOuterLinePath); pathAnimation('outer-line'); }; // 中心點至各頂點的直線繪製效果 var drawInnerLine = function() { d3.selectAll('.inner-line') .transition() .attr('x1', center.x) .attr('y1', center.y) .delay(800) .duration(300) .attrTween('x2', xTween) .attrTween('y2', yTween); }; // 資料區域連線的繪製效果 var drawChainLine = function() { d3.selectAll('.chain-line') .transition() .attr('x1', function(d) { return d.dataPoint.x; }) .attr('y1', function(d) { return d.dataPoint.y; }) .delay(function(d, i) { return 1200 + 200 * i; }) .duration(200) .attrTween('x2', chainXTween) .attrTween('y2', chainYTween) .transition() .delay(1200 + 200 * sides) .remove(); }; // 資料區域的進場 var drawDataArea = function() { d3.select('.data-area') .attr('d', getDataAreaPath) .transition() .delay(200 * sides + 1200) .duration(500) .styleTween('opacity', fadeIn); }; // Label的進場 var showLabel = function() { d3.selectAll('.label') .transition() .delay(function(d, i) { return (800 / sides) * i; }) .duration(800 / sides) .styleTween('opacity', fadeIn); }; // Value的進場 var showValue = function() { d3.selectAll('.value-label') .transition() .delay(800) .duration(300) .styleTween('opacity', fadeIn); }; // 線條的動畫 (x座標) var xTween = function(d) { var tween = d3.interpolate(center.x, d.vertex.x); return function(t) { return tween(t); } }; // 線條的動畫 (y座標) var yTween = function(d) { var tween = d3.interpolate(center.y, d.vertex.y); return function(t) { return tween(t); } }; // 資料區域連線的動畫 (x座標) var chainXTween = function(d, i) { var nextX = (i < sides - 1 ? dataset[i+1] : dataset[0]).dataPoint.x, tween = d3.interpolate(d.dataPoint.x, nextX); return function(t) { return tween(t); } }; // 資料區域連線的動畫 (y座標) var chainYTween = function(d, i) { var nextY = (i < sides - 1 ? dataset[i+1] : dataset[0]).dataPoint.y, tween = d3.interpolate(d.dataPoint.y, nextY); return function(t) { return tween(t); } }; // 淡入動畫 var fadeIn = function(d) { var tween = d3.interpolate(0, 1); return function(t) { return tween(t); } }; // 外邊線的動畫 (這個我用d3搞好久,只好用requestAniamtionFrame比較方便) var pathAnimation = function(elemId) { var path = document.getElementById(elemId), length = path.getTotalLength(), currentFrame = 0, totalFrames = 100, delay = delay || 0, progress, reqId; path.style.strokeDasharray = length + ' ' + length; path.style.strokeDashoffset = length; (function draw(timestamp) { progress = currentFrame / totalFrames; if (progress > 1) { window.cancelAnimationFrame(reqId); } else { currentFrame += 2; path.style.strokeDashoffset = Math.floor(length * (1 - progress)); reqId = window.requestAnimationFrame(draw); } })(); }; // 無法建立圖表或資料有問題時顯示的訊息 var warning = function(warnText) { d3.select('#container') .append('svg:svg') .attr('width', WIDTH) .attr('height', HEIGHT) .append('svg:text') .attr('transform', 'translate(' + WIDTH / 2 + ',' + HEIGHT / 2 + ')') .attr('class', 'warning') .text(warnText); }; return init();
})(window.d3);
// Author: Aaron Cho (aka 小狂)
Animated Ability Chart - Script Codes
Animated Ability Chart - Script Codes
Home Page Home
Developer AaronChuo (小狂)
Username aaronchuo
Uploaded September 11, 2022
Rating 3
Size 4,994 Kb
Views 32,384
Do you need developer help for Animated Ability Chart?

Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!

AaronChuo (小狂) (aaronchuo) Script Codes
Create amazing blog posts with AI!

Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!