UNPKG

d3-canvas-transition

Version:

Animated transitions for D3 selections on svg and canvas

168 lines (137 loc) 4.25 kB
import {selection, select} from 'd3-selection'; import {CanvasElement} from './element'; import resolution from './resolution'; import path from './attrs/path'; import {draw, redraw} from './draw'; var originalAttr = selection.prototype.attr; var defaultFactor; selection.prototype.attr = selectionAttr; selection.prototype.canvas = asCanvas; selection.prototype.canvasResolution = canvasResolution; selection.prototype.draw = drawNode; export default function selectCanvas (context, factor) { var s = selection(); if (!context) return s; if (isCanvas(context) && arguments.length === 1) return s.select(() => context); if (typeof(context) === 'string') { context = select(context).node(); if (!context) return s; } if (context.getContext) context = context.getContext('2d'); if (!context._rootElement) { if (!factor) factor = defaultFactor || resolution(); context._factor = factor; context._rootElement = new CanvasElement('canvas', context); } return s.select(() => context._rootElement); } function selectionAttr (name, value) { if (arguments.length > 1) { var node = this._parents[0] || this.node(), attr; if (isCanvas(node) && typeof(value.context) === 'function') { attr = value.pathObject; if (!attr) { attr = path(value); value.pathObject = attr; } if (!value.context()) value.context(wrapContext(node.context, node.factor)); arguments[1] = attr; } } return originalAttr.apply(this, arguments); } function isCanvas(node) { return node instanceof CanvasElement; } function asCanvas (reset) { var s = this, node = s.node(); if (node.tagName === 'CANVAS' && !isCanvas(node)) { s = selectCanvas(node); node = s.node(); } if (isCanvas(node) && reset) { var ctx = node.context, factor = node.factor, width = ctx.canvas.width, height = ctx.canvas.height; ctx.beginPath(); ctx.closePath(); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0, 0, width, height); if (factor > 1) { ctx.canvas.style.width = width + 'px'; ctx.canvas.style.height = height + 'px'; ctx.canvas.width = width * factor; ctx.canvas.height = height * factor; ctx.scale(factor, factor); } } return s; } function canvasResolution (value) { if (arguments.length === 1) { defaultFactor = value; return this; } return this.factor; } function drawNode () { var node = this.node(); if (isCanvas(node)) { var root = node.rootNode; if (root === node) redraw(node)(); else { if (root._scheduled) { root._scheduled = null; root._touches = 0; } draw(node); } } return this; } function wrapContext(context, factor) { if (factor === 1) return context; return new Context(context, factor); } function Context (context, factor) { this._context = context; this._factor = 1; this._f = factor; } Context.prototype = { beginPath () { this._context.beginPath(); }, closePath () { this._context.closePath(); }, moveTo (x, y) { this._context.moveTo(this._f*x, this._f*y); }, lineTo (x, y) { this._context.lineTo(this._f*x, this._f*y); }, arc () { arguments[0] = this._f*arguments[0]; arguments[1] = this._f*arguments[1]; arguments[2] = this._f*arguments[2]; this._context.arc.apply(this._context, arguments); }, rect (x, y, w, h) { this._context.rect(this._f*x, this._f*y, this._f*w, this._f*h); }, quadraticCurveTo (cpx, cpy, x, y) { this._context.quadraticCurveTo(this._f*cpx, this._f*cpy, this._f*x, this._f*y); }, bezierCurveTo (cp1x,cp1y,cp2x,cp2y,x,y) { this._context.bezierCurveTo( this._f*cp1x, this._f*cp1y, this._f*cp2x, this._f*cp2y, this._f*x, this._f*y ); } };