agentscript
Version:
AgentScript Model in Model/View architecture
433 lines (388 loc) • 29.3 kB
HTML
<html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Source: domUtils.js</title><!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="dark"><div class="sidebar-container"><div class="sidebar" id="sidebar"><a href="/" class="sidebar-title sidebar-title-anchor">Home</a><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="0TyI9v7-OL-7m0zm2RwjA"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="AgentArray.html">AgentArray</a></div><div class="sidebar-section-children"><a href="AgentList.html">AgentList</a></div><div class="sidebar-section-children"><a href="AgentSet.html">AgentSet</a></div><div class="sidebar-section-children"><a href="Animator.html">Animator</a></div><div class="sidebar-section-children"><a href="DataSet.html">DataSet</a></div><div class="sidebar-section-children"><a href="GUI.html">GUI</a></div><div class="sidebar-section-children"><a href="GeoDataSet.html">GeoDataSet</a></div><div class="sidebar-section-children"><a href="Keyboard.html">Keyboard</a></div><div class="sidebar-section-children"><a href="Link.html">Link</a></div><div class="sidebar-section-children"><a href="Links.html">Links</a></div><div class="sidebar-section-children"><a href="Model.html">Model</a></div><div class="sidebar-section-children"><a href="Model3D.html">Model3D</a></div><div class="sidebar-section-children"><a href="Mouse.html">Mouse</a></div><div class="sidebar-section-children"><a href="Patch.html">Patch</a></div><div class="sidebar-section-children"><a href="Patches.html">Patches</a></div><div class="sidebar-section-children"><a href="RGBDataSet.html">RGBDataSet</a></div><div class="sidebar-section-children"><a href="ThreeDraw.html">ThreeDraw</a></div><div class="sidebar-section-children"><a href="Turtle.html">Turtle</a></div><div class="sidebar-section-children"><a href="Turtle3D.html">Turtle3D</a></div><div class="sidebar-section-children"><a href="Turtles.html">Turtles</a></div><div class="sidebar-section-children"><a href="TwoDraw.html">TwoDraw</a></div><div class="sidebar-section-children"><a href="World.html">World</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="0-dkdzCzOcPNpffpBnrfK"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-src_geojson.html">src/geojson</a></div><div class="sidebar-section-children"><a href="module-src_gis.html">src/gis</a></div><div class="sidebar-section-children"><a href="module-src_jsUtils.html">src/jsUtils</a></div><div class="sidebar-section-children"><a href="module-src_steg.html">src/steg</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="SBOquGgyp1l-UZr1eZFHK"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#imagePromise">imagePromise</a></div><div class="sidebar-section-children"><a href="global.html#createCanvas">createCanvas</a></div><div class="sidebar-section-children"><a href="global.html#createCtx">createCtx</a></div><div class="sidebar-section-children"><a href="global.html#setCtxImage">setCtxImage</a></div><div class="sidebar-section-children"><a href="global.html#toWindow">toWindow</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"><div class="navbar-item"><a id="github" href="https://github.com/backspaces/agentscript" target="">Github</a></div><div class="navbar-item"><a id="npm" href="https://www.npmjs.com/package/agentscript" target="">npm</a></div></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">domUtils.js</h1></header><article><pre class="prettyprint source lang-js"><code>import {
inWorker,
inMain,
inDeno,
typeOf,
isDataSet,
isTypedArray,
isObject,
step,
} from './jsUtils.js'
// function inWorker() {
// // return !inNode() && typeof self.window === 'undefined'
// return globalThis.WorkerGlobalScope !== undefined
// }
// ### Async & I/O
// download canvas as png or jpeg. Canvas can be a dataURL.
// quality is default. For lossless jpeg, set to 1
export function downloadCanvas(can, name = 'download.png', quality = null) {
if (!(name.endsWith('.png') || name.endsWith('.jpeg'))) name = name + '.png'
const type = name.endsWith('.png') ? 'image/png' : 'image/jpeg'
const url = typeOf(can) === 'string' ? can : can.toDataURL(type, quality)
const link = document.createElement('a')
link.download = name
link.href = url
link.click()
}
// blobable = ArrayBuffer, ArrayBufferView, Blob, String
// Objects & Arrays too, converted to json
export function downloadBlob(blobable, name = 'download', format = true) {
if (isDataSet(blobable) && !Array.isArray(blobable.data))
blobable.data = Array.from(blobable.data)
if (isTypedArray(blobable)) blobable = Array.from(blobable)
if (isObject(blobable) || Array.isArray(blobable))
blobable = format
? JSON.stringify(blobable, null, 2)
: JSON.stringify(blobable)
const blob = typeOf(blobable) === 'blob' ? blobable : new Blob([blobable])
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.download = name
link.href = url
link.click()
URL.revokeObjectURL(url)
}
// ### Canvas & Image
/**
* Return a Promise for getting an image.
*
* use: imagePromise('./path/to/img').then(img => imageFcn(img))
* or: await imagePromise('./path/to/img')
*
* @param {string} url URL for path to image
* @returns {Promise} A promise resolving to the image
*/
export async function imagePromise(url, preferDOM = true) {
// if (inMain() || inDeno()) {
if ((inMain() && preferDOM) || inDeno()) {
return new Promise((resolve, reject) => {
const img = new Image()
img.crossOrigin = 'Anonymous'
img.onload = () => resolve(img)
img.onerror = () => reject(`Could not load image ${url}`)
img.src = url
})
// } else if (inDeno()) {
// // return loadImage(url)
// console.log('inDeno: url', url, 'Image', Image)
// const img = new Image(url) // needs install in deno function
// console.log('inDeno: img', img)
// await pause(1000)
// console.log('inDeno: img', img)
// return img
} else if (inWorker() || !preferDOM) {
// { mode: 'cors' } ?
const blob = await fetch(url).then(response => response.blob())
return createImageBitmap(blob)
}
}
// export function imageSize(img) {
// if (inDeno()) {
// return [img.width(), img.height()]
// } else {
// return [img.width, img.height]
// }
// }
// function offscreenOK() {
// // return !!self.OffscreenCanvas
// // return typeof OffscreenCanvas !== 'undefined'
// return inWorker()
// }
/**
* Create a blank 2D canvas of a given width/height.
*
* @param {number} width The canvas height in pixels
* @param {number} height The canvas width in pixels
* @param {boolean} [preferDOM=false] If false, return "Offscreen" canvas
* @returns {Canvas} The resulting Canvas object
*/
// export function createCanvas(width, height, offscreen = offscreenOK()) {
// if (offscreen) return new OffscreenCanvas(width, height)
// const can = document.createElement('canvas')
// can.width = width
// can.height = height
// return can
// }
export function createCanvas(width, height, preferDOM = true) {
if (inMain() && preferDOM) {
const can = document.createElement('canvas')
can.width = width
can.height = height
return can
} else if (inDeno()) {
return globalThis.createCanvas(width, height)
} else if (inWorker() || !preferDOM) {
return new OffscreenCanvas(width, height)
}
}
/**
* As above, but returing the 2D context object instead of the canvas.
* Note ctx.canvas is the canvas for the ctx, and can be use as an image.
*
* @param {number} width The canvas height in pixels
* @param {number} height The canvas width in pixels
* @param {boolean} [offscreen=offscreenOK()] If true, return "Offscreen" canvas
* @returns {Context2D} The resulting Canvas's 2D context
*/
export function createCtx(width, height, preferDOM = true, attrs = {}) {
// const can = createCanvas(width, height, offscreen)
// return can.getContext('2d', attrs)
const can = createCanvas(width, height, preferDOM)
const ctx = can.getContext('2d', attrs)
if (inDeno()) {
const ctxObj = {
canvas: can,
}
Object.setPrototypeOf(ctxObj, ctx)
return ctxObj
} else {
return ctx
}
}
// FIX or drop
// Duplicate a canvas, preserving it's current image/drawing
export function cloneCanvas(can, preferDOM = true) {
const ctx = createCtx(can.width, can.height, preferDOM)
ctx.drawImage(can, 0, 0)
return ctx.canvas
}
// Resize a ctx in-place and preserve image. SpriteSheet
export function resizeCtx(ctx, width, height) {
const copy = cloneCanvas(ctx.canvas)
ctx.canvas.width = width
ctx.canvas.height = height
ctx.drawImage(copy, 0, 0)
}
// // Return new canvas scaled by width, height and preserve image.
// export function resizeCanvas(
// can,
// width,
// height = (width / can.width) * can.height
// ) {
// const ctx = createCtx(width, height)
// ctx.drawImage(can, 0, 0, width, height)
// return ctx.canvas
// }
// Set the ctx/canvas size if differs from width/height.
// It does not install a transform and assumes there is not one currently installed.
// The World object can do that for AgentSets.
// Can move to World
export function setCanvasSize(can, width, height) {
if (can.width !== width || can.height != height) {
can.width = width
can.height = height
}
}
// export function canvasToImage(can) {
// var img = new Image()
// img.src = can.toDataURL()
// }
// Install identity transform for this context.
// Call ctx.restore() to revert to previous transform.
export function setIdentity(ctx) {
ctx.save() // NOTE: Does not change state, only saves current state.
ctx.resetTransform() // or ctx.setTransform(1, 0, 0, 1, 0, 0)
}
// Set the text font, align and baseline drawing parameters.
// Ctx can be either a canvas context or a DOM element
// See [reference](http://goo.gl/AvEAq) for details.
// * font is a HTML/CSS string like: "9px sans-serif"
// * align is left right center start end
// * baseline is top hanging middle alphabetic ideographic bottom
export function setTextProperties(
ctx,
font,
textAlign = 'center',
textBaseline = 'middle'
) {
Object.assign(ctx, { font, textAlign, textBaseline })
}
// bboxCtx is reused on every call to stringMetrics
// const bboxCtx = createCtx(0, 0)
let bboxCtx
export function stringMetrics(
string,
font,
textAlign = 'center',
textBaseline = 'middle'
) {
// bboxCtx ??= createCtx(0, 0)
if (!bboxCtx) bboxCtx = createCtx(0, 0)
setTextProperties(bboxCtx, font, textAlign, textBaseline)
const metrics = bboxCtx.measureText(string)
metrics.height = // not sure how safe this is but..
metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent
return metrics
}
// Draw string of the given color at the xy location, in ctx pixel coords.
// Use setIdentity .. reset if a transform is being used by caller.
export function drawText(ctx, string, x, y, color, useIdentity = true) {
if (useIdentity) setIdentity(ctx)
ctx.fillStyle = color.css || color // OK to use Color.typedColor
ctx.fillText(string, x, y)
if (useIdentity) ctx.restore()
}
// Return the (complete) ImageData object for this context object
export function ctxImageData(ctx) {
return ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height)
}
// Return ctx data as an array of typed array rgba colors
export function ctxImageColors(ctx) {
const typedArray = ctxImageData(ctx).data
const colors = []
step(typedArray.length, 4, i => colors.push(typedArray.subarray(i, i + 4)))
return colors
}
// Return ctx data as an array of Uint32Array rgba pixels
export function ctxImagePixels(ctx) {
const imageData = ctxImageData(ctx)
const pixels = new Uint32Array(imageData.data.buffer)
return pixels
}
// Clear this context using the cssColor.
// If no color or if color === 'transparent', clear to transparent.
export function clearCtx(ctx, cssColor = undefined) {
const { width, height } = ctx.canvas
setIdentity(ctx)
if (!cssColor || cssColor === 'transparent') {
ctx.clearRect(0, 0, width, height)
} else {
cssColor = cssColor.css || cssColor
ctx.fillStyle = cssColor
ctx.fillRect(0, 0, width, height)
}
ctx.restore()
}
// These image functions use "imagable" objects: Image, ImageBitmap, Canvas ...
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasImageSource
export function imageToCtx(img) {
// const [width, height] = imageSize(img)
const { width, height } = img
const ctx = createCtx(width, height)
// const ctx = createCtx(img.width, img.height)
fillCtxWithImage(ctx, img)
return ctx
}
export function imageToCanvas(img) {
return imageToCtx(img).canvas
}
// Fill this context with the given image. Will scale image to fit ctx size.
export function fillCtxWithImage(ctx, img) {
setIdentity(ctx) // set/restore identity
ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height)
ctx.restore()
}
/**
* Fill this context with the given image, resizing it to img size if needed.
*
* @param {Context2D} ctx a canvas 2D context
* @param {Image} img the Image to install in this ctx
*/
export function setCtxImage(ctx, img) {
setCanvasSize(ctx.canvas, img.width, img.height)
fillCtxWithImage(ctx, img)
}
// ### Debug
/**
* Merge a module's obj key/val pairs into to the global/window namespace.
* Primary use is to make console logging easier when debugging
* modules.
*
* @param {Object} obj Object who's key/val pairs will be installed in window.
*/
export function toWindow(obj) {
Object.assign(window, obj)
console.log('toWindow:', Object.keys(obj).join(', '))
}
export function dump(model = window.model) {
const { patches: ps, turtles: ts, links: ls } = model
Object.assign(window, { ps, ts, ls })
window.p = ps.length > 0 ? ps.oneOf() : {}
window.t = ts.length > 0 ? ts.oneOf() : {}
window.l = ls.length > 0 ? ls.oneOf() : {}
console.log('debug: ps, ts, ls, p, t, l dumped to window')
}
// ### Dom
export function addCssLink(url) {
const link = document.createElement('link')
link.setAttribute('rel', 'stylesheet')
link.setAttribute('href', url)
document.head.appendChild(link)
}
export async function fetchCssStyle(url) {
if (url.startsWith('../')) {
console.log('fetchCssStyle relative url', url)
url = import.meta.resolve(url)
console.log(' absolute url', url)
}
const response = await fetch(url)
if (!response.ok) throw Error(`fetchCssStyle: Not found: ${url}`)
const css = await response.text()
addCssStyle(css)
return css
}
export function addCssStyle(css) {
// document.head.innerHTML += `<style>${css}</style>`
const style = document.createElement('style')
style.innerHTML = css
document.head.appendChild(style)
}
// REST:
// Parse the query, returning an object of key / val pairs.
export function getQueryString() {
return window.location.search.substr(1)
}
export function parseQueryString(
// paramsString = window.location.search.substr(1)
paramsString = getQueryString()
) {
const results = {}
const searchParams = new URLSearchParams(paramsString)
for (const pair of searchParams.entries()) {
let [key, val] = pair
if (val.match(/^[0-9.]+$/) || val.match(/^[0-9.]+e[0-9]+$/))
val = Number(val)
if (['true', 't', ''].includes(val)) val = true
if (['false', 'f'].includes(val)) val = false
results[key] = val
}
return results
}
// Merge the querystring into the default parameters
export function RESTapi(parameters) {
return Object.assign(parameters, parseQueryString())
}
// Print a message to an html element
// Default to document.body if in browser.
// If msg is an object, convert to JSON
// (object canot have cycles etc)
// If element is string, find element by ID
export function printToPage(msg, element = document.body) {
// if (isObject(msg)) {
if (typeof msg === 'object') {
msg = JSON.stringify(msg, null, 2)
// msg = '<pre>' + msg + '</pre>'
}
msg = '<pre>' + msg + '</pre>'
if (typeof element === 'string') {
element = document.getElementById(element)
}
element.style.fontFamily = 'monospace'
element.innerHTML += msg //+ '<br />'
}
// Get element (i.e. canvas) relative x,y position from event/mouse position.
// http://goo.gl/356S91
export function getEventXY(element, evt) {
const rect = element.getBoundingClientRect()
return [evt.clientX - rect.left, evt.clientY - rect.top]
}
// ### Math
// ### Geometry
// ### Models
// ### Arrays, Objects and Iteration
// ### OofA/AofO
// ### Types
// could have some of the types that are dom oriented. TypedArrays too?
</code></pre></article></section><footer class="footer" id="PeOAagUepe"><div class="wrapper">AgentScript version: 0.10.19 using clean-jsdoc-theme</div></footer></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><a href="/" class="sidebar-title sidebar-title-anchor">Home</a><div class="mobile-nav-links"><div class="navbar-item"><a id="github-mobile" href="https://github.com/backspaces/agentscript" target="">Github</a></div><div class="navbar-item"><a id="npm-mobile" href="https://www.npmjs.com/package/agentscript" target="">npm</a></div></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="0TyI9v7-OL-7m0zm2RwjA"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="AgentArray.html">AgentArray</a></div><div class="sidebar-section-children"><a href="AgentList.html">AgentList</a></div><div class="sidebar-section-children"><a href="AgentSet.html">AgentSet</a></div><div class="sidebar-section-children"><a href="Animator.html">Animator</a></div><div class="sidebar-section-children"><a href="DataSet.html">DataSet</a></div><div class="sidebar-section-children"><a href="GUI.html">GUI</a></div><div class="sidebar-section-children"><a href="GeoDataSet.html">GeoDataSet</a></div><div class="sidebar-section-children"><a href="Keyboard.html">Keyboard</a></div><div class="sidebar-section-children"><a href="Link.html">Link</a></div><div class="sidebar-section-children"><a href="Links.html">Links</a></div><div class="sidebar-section-children"><a href="Model.html">Model</a></div><div class="sidebar-section-children"><a href="Model3D.html">Model3D</a></div><div class="sidebar-section-children"><a href="Mouse.html">Mouse</a></div><div class="sidebar-section-children"><a href="Patch.html">Patch</a></div><div class="sidebar-section-children"><a href="Patches.html">Patches</a></div><div class="sidebar-section-children"><a href="RGBDataSet.html">RGBDataSet</a></div><div class="sidebar-section-children"><a href="ThreeDraw.html">ThreeDraw</a></div><div class="sidebar-section-children"><a href="Turtle.html">Turtle</a></div><div class="sidebar-section-children"><a href="Turtle3D.html">Turtle3D</a></div><div class="sidebar-section-children"><a href="Turtles.html">Turtles</a></div><div class="sidebar-section-children"><a href="TwoDraw.html">TwoDraw</a></div><div class="sidebar-section-children"><a href="World.html">World</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="0-dkdzCzOcPNpffpBnrfK"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-src_geojson.html">src/geojson</a></div><div class="sidebar-section-children"><a href="module-src_gis.html">src/gis</a></div><div class="sidebar-section-children"><a href="module-src_jsUtils.html">src/jsUtils</a></div><div class="sidebar-section-children"><a href="module-src_steg.html">src/steg</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="SBOquGgyp1l-UZr1eZFHK"><div>Global</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="global.html#imagePromise">imagePromise</a></div><div class="sidebar-section-children"><a href="global.html#createCanvas">createCanvas</a></div><div class="sidebar-section-children"><a href="global.html#createCtx">createCtx</a></div><div class="sidebar-section-children"><a href="global.html#setCtxImage">setCtxImage</a></div><div class="sidebar-section-children"><a href="global.html#toWindow">toWindow</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>