UNPKG

d3-view

Version:

View-model d3 plugin for building interactive data-driven web interfaces

90 lines (78 loc) • 2.38 kB
import { select, selection } from "d3-selection"; import slice from "../utils/slice"; import warn from "../utils/warn"; import getdirs from "./getdirs"; // Extend selection prototype with new methods selection.prototype.mount = mount; selection.prototype.view = view; selection.prototype.model = model; selection.prototype.directives = directives; function directives(vm) { const node = this.node(); let dirs = node.__d3_directives__; if (dirs === undefined) { dirs = getdirs(node, vm); // no point in storing the directive object if there are no directives or the node is not a component node.__d3_directives__ = dirs.size() || getComponent(node, vm) ? dirs : null; } return dirs ? dirs : getdirs(node); } function model() { var vm = this.view(); return vm ? vm.model : null; } function view(value) { if (arguments.length) { return this.property("__d3_view__", value); } else { var element = this.node(), view = element ? element.__d3_view__ : null, parent = element ? element.parentNode : null; while (parent && !view) { view = parent.__d3_view__; parent = parent.parentNode; } return view; } } // // mount function on a d3 selection // Use this function to mount the selection // This method returns nothing or a promise function mount(data) { var promises = []; this.each(function() { var view = select(this).view(); if (view) promises.push(mountElement(this, view, data)); else warn("Cannot mount, no view object available to mount to"); }); return Promise.all(promises); } // INTERNALS // mount an element into a given model const mountElement = (element, vm, data) => { if (!element || !element.tagName) return; var component = getComponent(element, vm), directives = select(element).directives(vm), preMount = directives.preMount(); if (preMount) return preMount.execute(vm.model); else { if (component) { return component({ parent: vm }) .mount(element, data) .then(cm => { directives.execute(cm.model); return cm; }); } else { directives.execute(vm.model); return Promise.all( slice(element.children).map(c => mountElement(c, vm, data)) ); } } }; const getComponent = (element, vm) => { return vm.components.get(element.tagName.toLowerCase()); };