CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
index.mjs392 linesDownload Raw Back to canvas
1/*2The canvas renderer was written by Yue Dong.3 4Modifications tracked on Github.5*/6 7/* global OffscreenCanvas */8 9import * as util from '../../../util/index.mjs';10import * as is from '../../../is.mjs';11import { makeBoundingBox } from '../../../math.mjs';12import { labelHalign, labelValign } from '../../../style/align.mjs';13import ElementTextureCache from './ele-texture-cache.mjs';14import LayeredTextureCache from './layered-texture-cache.mjs';15 16import arrowShapes from './arrow-shapes.mjs';17import drawingElements from './drawing-elements.mjs';18import drawingEdges from './drawing-edges.mjs';19import drawingImages from './drawing-images.mjs';20import drawingLabelText from './drawing-label-text.mjs';21import drawingNodes from './drawing-nodes.mjs';22import drawingRedraw from './drawing-redraw.mjs';23import drawingRedrawWebGL from './webgl/drawing-redraw-webgl.mjs';24import drawingShapes from './drawing-shapes.mjs';25import exportImage from './export-image.mjs';26import nodeShapes from './node-shapes.mjs';27 28var CR = CanvasRenderer;29var CRp = CanvasRenderer.prototype;30 31CRp.CANVAS_LAYERS = 3;32//33CRp.SELECT_BOX = 0;34CRp.DRAG = 1;35CRp.NODE = 2;36CRp.WEBGL = 3;37 38CRp.CANVAS_TYPES = [ '2d', '2d', '2d', 'webgl2' ];39 40CRp.BUFFER_COUNT = 3;41//42CRp.TEXTURE_BUFFER = 0;43CRp.MOTIONBLUR_BUFFER_NODE = 1;44CRp.MOTIONBLUR_BUFFER_DRAG = 2;45 46function CanvasRenderer( options ){47  var r = this;48 49  var containerWindow = r.cy.window();50  var document = containerWindow.document;51 52  if( options.webgl ){53    CRp.CANVAS_LAYERS = r.CANVAS_LAYERS = 4;54    console.log('webgl rendering enabled');55  }56 57  r.data = {58    canvases: new Array( CRp.CANVAS_LAYERS ),59    contexts: new Array( CRp.CANVAS_LAYERS ),60    canvasNeedsRedraw: new Array( CRp.CANVAS_LAYERS ),61 62    bufferCanvases: new Array( CRp.BUFFER_COUNT ),63    bufferContexts: new Array( CRp.CANVAS_LAYERS ),64  };65 66  var tapHlOffAttr = '-webkit-tap-highlight-color';67  var tapHlOffStyle = 'rgba(0,0,0,0)';68  r.data.canvasContainer = document.createElement( 'div' ); // eslint-disable-line no-undef69  var containerStyle = r.data.canvasContainer.style;70  r.data.canvasContainer.style[tapHlOffAttr] = tapHlOffStyle;71  containerStyle.position = 'relative';72  containerStyle.zIndex = '0';73  containerStyle.overflow = 'hidden';74 75  var container = options.cy.container();76  container.appendChild( r.data.canvasContainer );77  container.style[tapHlOffAttr] = tapHlOffStyle;78 79  var styleMap = {80    '-webkit-user-select': 'none',81    '-moz-user-select': '-moz-none',82    'user-select': 'none',83    '-webkit-tap-highlight-color': 'rgba(0,0,0,0)',84    'outline-style': 'none',85  };86 87  if(is.ms()) {88    styleMap['-ms-touch-action'] = 'none';89    styleMap['touch-action'] = 'none';90  }91 92  for( var i = 0; i < CRp.CANVAS_LAYERS; i++ ){93    var canvas = r.data.canvases[ i ] = document.createElement( 'canvas' );  // eslint-disable-line no-undef94    var type = CRp.CANVAS_TYPES[ i ];95    r.data.contexts[ i ] = canvas.getContext( type );96    if( !r.data.contexts[ i ] ) {97      util.error( 'Could not create canvas of type ' + type );98    }99    Object.keys(styleMap).forEach((k) => {100      canvas.style[k] = styleMap[k];101    });102    canvas.style.position = 'absolute';103    canvas.setAttribute( 'data-id', 'layer' + i );104    canvas.style.zIndex = String( CRp.CANVAS_LAYERS - i );105    r.data.canvasContainer.appendChild( canvas );106 107    r.data.canvasNeedsRedraw[ i ] = false;108  }109  r.data.topCanvas = r.data.canvases[0];110 111  r.data.canvases[ CRp.NODE ].setAttribute( 'data-id', 'layer' + CRp.NODE + '-node' );112  r.data.canvases[ CRp.SELECT_BOX ].setAttribute( 'data-id', 'layer' + CRp.SELECT_BOX + '-selectbox' );113  r.data.canvases[ CRp.DRAG ].setAttribute( 'data-id', 'layer' + CRp.DRAG + '-drag' );114  if( r.data.canvases[ CRp.WEBGL ] ) {115    r.data.canvases[ CRp.WEBGL ].setAttribute( 'data-id', 'layer' + CRp.WEBGL + '-webgl' );116  }117 118  for( var i = 0; i < CRp.BUFFER_COUNT; i++ ){119    r.data.bufferCanvases[ i ] = document.createElement( 'canvas' );  // eslint-disable-line no-undef120    r.data.bufferContexts[ i ] = r.data.bufferCanvases[ i ].getContext( '2d' );121    r.data.bufferCanvases[ i ].style.position = 'absolute';122    r.data.bufferCanvases[ i ].setAttribute( 'data-id', 'buffer' + i );123    r.data.bufferCanvases[ i ].style.zIndex = String( -i - 1 );124    r.data.bufferCanvases[ i ].style.visibility = 'hidden';125    //r.data.canvasContainer.appendChild(r.data.bufferCanvases[i]);126  }127 128  r.pathsEnabled = true;129 130  let emptyBb = makeBoundingBox();131 132  let getBoxCenter = bb => ({ x: (bb.x1 + bb.x2)/2, y: (bb.y1 + bb.y2)/2 });133 134  let getCenterOffset = bb => ({ x: -bb.w/2, y: -bb.h/2 });135 136  let backgroundTimestampHasChanged = ele => {137    let _p = ele[0]._private;138    let same = _p.oldBackgroundTimestamp === _p.backgroundTimestamp;139 140    return !same;141  };142 143  let getStyleKey = ele => ele[0]._private.nodeKey;144  let getLabelKey = ele => ele[0]._private.labelStyleKey;145  let getSourceLabelKey = ele => ele[0]._private.sourceLabelStyleKey;146  let getTargetLabelKey = ele => ele[0]._private.targetLabelStyleKey;147 148  let drawElement = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElement( context, ele, bb, false, false, useEleOpacity );149  let drawLabel = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElementText( context, ele, bb, scaledLabelShown, 'main', useEleOpacity );150  let drawSourceLabel = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElementText( context, ele, bb, scaledLabelShown, 'source', useEleOpacity );151  let drawTargetLabel = (context, ele, bb, scaledLabelShown, useEleOpacity) => r.drawElementText( context, ele, bb, scaledLabelShown, 'target', useEleOpacity );152 153  let getElementBox = ele => { ele.boundingBox(); return ele[0]._private.bodyBounds; };154  let getLabelBox   = ele => { ele.boundingBox(); return ele[0]._private.labelBounds.main || emptyBb; };155  let getSourceLabelBox = ele => { ele.boundingBox(); return ele[0]._private.labelBounds.source || emptyBb; };156  let getTargetLabelBox = ele => { ele.boundingBox(); return ele[0]._private.labelBounds.target || emptyBb; };157 158  let isLabelVisibleAtScale = (ele, scaledLabelShown) => scaledLabelShown;159 160  let getElementRotationPoint = ele => getBoxCenter( getElementBox(ele) );161 162  let addTextMargin = (prefix, pt, ele) => {163    let pre = prefix ? prefix + '-' : '';164 165    return {166      x: pt.x + ele.pstyle(pre + 'text-margin-x').pfValue,167      y: pt.y + ele.pstyle(pre + 'text-margin-y').pfValue168    };169  };170 171  let getRsPt = (ele, x, y) => {172    let rs = ele[0]._private.rscratch;173 174    return { x: rs[x], y: rs[y] };175  };176 177  let getLabelRotationPoint = ele => addTextMargin('', getRsPt(ele, 'labelX', 'labelY'), ele);178  let getSourceLabelRotationPoint = ele => addTextMargin('source', getRsPt(ele, 'sourceLabelX', 'sourceLabelY'), ele);179  let getTargetLabelRotationPoint = ele => addTextMargin('target', getRsPt(ele, 'targetLabelX', 'targetLabelY'), ele);180 181  let getElementRotationOffset = ele => getCenterOffset( getElementBox(ele) );182  let getSourceLabelRotationOffset = ele => getCenterOffset( getSourceLabelBox(ele) );183  let getTargetLabelRotationOffset = ele => getCenterOffset( getTargetLabelBox(ele) );184 185  let getLabelRotationOffset = ele => {186    let bb = getLabelBox(ele);187    let p = getCenterOffset( getLabelBox(ele) );188 189    if( ele.isNode() ){190      switch( labelHalign( ele.pstyle('text-halign').value ) ){191        case 'left':192          p.x = -bb.w - (bb.leftPad || 0);193          break;194        case 'right':195          p.x = -(bb.rightPad || 0);196          break;197      }198 199      switch( labelValign( ele.pstyle('text-valign').value ) ){200        case 'top':201          p.y = -bb.h - (bb.topPad || 0);202          break;203        case 'bottom':204          p.y = -(bb.botPad || 0);205          break;206      }207    }208 209    return p;210  };211 212  let eleTxrCache = r.data.eleTxrCache = new ElementTextureCache( r, {213    getKey: getStyleKey,214    doesEleInvalidateKey: backgroundTimestampHasChanged,215    drawElement: drawElement,216    getBoundingBox: getElementBox,217    getRotationPoint: getElementRotationPoint,218    getRotationOffset: getElementRotationOffset,219    allowEdgeTxrCaching: false,220    allowParentTxrCaching: false221  } );222 223  let lblTxrCache = r.data.lblTxrCache = new ElementTextureCache( r, {224    getKey: getLabelKey,225    drawElement: drawLabel,226    getBoundingBox: getLabelBox,227    getRotationPoint: getLabelRotationPoint,228    getRotationOffset: getLabelRotationOffset,229    isVisible: isLabelVisibleAtScale230  } );231 232  let slbTxrCache = r.data.slbTxrCache = new ElementTextureCache( r, {233    getKey: getSourceLabelKey,234    drawElement: drawSourceLabel,235    getBoundingBox: getSourceLabelBox,236    getRotationPoint: getSourceLabelRotationPoint,237    getRotationOffset: getSourceLabelRotationOffset,238    isVisible: isLabelVisibleAtScale239  } );240 241  let tlbTxrCache = r.data.tlbTxrCache = new ElementTextureCache( r, {242    getKey: getTargetLabelKey,243    drawElement: drawTargetLabel,244    getBoundingBox: getTargetLabelBox,245    getRotationPoint: getTargetLabelRotationPoint,246    getRotationOffset: getTargetLabelRotationOffset,247    isVisible: isLabelVisibleAtScale248  } );249 250  let lyrTxrCache = r.data.lyrTxrCache = new LayeredTextureCache( r );251 252  r.onUpdateEleCalcs(function invalidateTextureCaches( willDraw, eles ){253    // each cache should check for sub-key diff to see that the update affects that cache particularly254    eleTxrCache.invalidateElements( eles );255    lblTxrCache.invalidateElements( eles );256    slbTxrCache.invalidateElements( eles );257    tlbTxrCache.invalidateElements( eles );258 259    // any change invalidates the layers260    lyrTxrCache.invalidateElements( eles );261 262    // update the old bg timestamp so diffs can be done in the ele txr caches263    for( let i = 0; i < eles.length; i++ ){264      let _p = eles[i]._private;265 266      _p.oldBackgroundTimestamp = _p.backgroundTimestamp;267    }268  });269 270  let refineInLayers = reqs => {271    for( var i = 0; i < reqs.length; i++ ){272      lyrTxrCache.enqueueElementRefinement( reqs[i].ele );273    }274  };275 276  eleTxrCache.onDequeue(refineInLayers);277  lblTxrCache.onDequeue(refineInLayers);278  slbTxrCache.onDequeue(refineInLayers);279  tlbTxrCache.onDequeue(refineInLayers);280 281  if( options.webgl ) {282    r.initWebgl( options, {283      getStyleKey,284      getLabelKey,285      getSourceLabelKey,286      getTargetLabelKey,287      drawElement,288      drawLabel,289      drawSourceLabel,290      drawTargetLabel,291      getElementBox,292      getLabelBox,293      getSourceLabelBox,294      getTargetLabelBox,295      getElementRotationPoint,296      getElementRotationOffset,297      getLabelRotationPoint,298      getSourceLabelRotationPoint,299      getTargetLabelRotationPoint,300      getLabelRotationOffset,301      getSourceLabelRotationOffset,302      getTargetLabelRotationOffset303    } );304  }305}306 307CRp.redrawHint = function( group, bool ){308  var r = this;309  310  switch( group ){311    case 'eles':312      r.data.canvasNeedsRedraw[ CRp.NODE ] = bool;313      break;314    case 'drag':315      r.data.canvasNeedsRedraw[ CRp.DRAG ] = bool;316      break;317    case 'select':318      r.data.canvasNeedsRedraw[ CRp.SELECT_BOX ] = bool;319      break;320    case 'gc':321      r.data.gc = true;322      break;323  }324};325 326// whether to use Path2D caching for drawing327var pathsImpld = typeof Path2D !== 'undefined';328 329CRp.path2dEnabled = function( on ){330  if( on === undefined ){331    return this.pathsEnabled;332  }333 334  this.pathsEnabled = on ? true : false;335};336 337CRp.usePaths = function(){338  return pathsImpld && this.pathsEnabled;339};340 341CRp.setImgSmoothing = function( context, bool ){342  if( context.imageSmoothingEnabled != null ){343    context.imageSmoothingEnabled = bool;344  } else {345    context.webkitImageSmoothingEnabled = bool;346    context.mozImageSmoothingEnabled = bool;347    context.msImageSmoothingEnabled = bool;348  }349};350 351CRp.getImgSmoothing = function( context ){352  if( context.imageSmoothingEnabled != null ){353    return context.imageSmoothingEnabled;354  } else {355    return context.webkitImageSmoothingEnabled || context.mozImageSmoothingEnabled || context.msImageSmoothingEnabled;356  }357};358 359CRp.makeOffscreenCanvas = function(width, height){360  let canvas;361 362  if( typeof OffscreenCanvas !== typeof undefined ){363    canvas = new OffscreenCanvas(width, height);364  } else {365    var containerWindow = this.cy.window();366    var document = containerWindow.document;367    canvas = document.createElement('canvas'); // eslint-disable-line no-undef368    canvas.width = width;369    canvas.height = height;370  }371 372  return canvas;373};374 375[376  arrowShapes,377  drawingElements,378  drawingEdges,379  drawingImages,380  drawingLabelText,381  drawingNodes,382  drawingRedraw,383  drawingRedrawWebGL,384  drawingShapes,385  exportImage,386  nodeShapes387].forEach( function( props ){388  util.extend( CRp, props );389} );390 391export default CR;392 
basant307/AI_Governance_Project · CoolFace