scrawl-canvas
Version:
Version 8.9.4 - 19 Nov 2022
779 lines (506 loc) • 33.1 kB
HTML
<html>
<head>
<title>Demo Snippets 004</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<link rel="stylesheet" media="all" href="../../docco.css" />
</head>
<body>
<div id="container">
<div id="background"></div>
<ul id="jump_to">
<li>
<a class="large" href="javascript:void(0);">Jump To …</a>
<a class="small" href="javascript:void(0);">+</a>
<div id="jump_wrapper">
<div id="jump_page_wrapper">
<div id="jump_page">
<a class="source" href="../modules/canvas-minimap.html">
./demo/modules/canvas-minimap.js
</a>
<a class="source" href="../modules/canvas-scene-editor.html">
./demo/modules/canvas-scene-editor.js
</a>
<a class="source" href="../modules/dom-entity-editor.html">
./demo/modules/dom-entity-editor.js
</a>
<a class="source" href="../modules/entity-copy-paste.html">
./demo/modules/entity-copy-paste.js
</a>
<a class="source" href="../modules/entity-manipulation-gui.html">
./demo/modules/entity-manipulation-gui.js
</a>
<a class="source" href="../modules/entity-navigation.html">
./demo/modules/entity-navigation.js
</a>
<a class="source" href="../modules/entity-ring-builder.html">
./demo/modules/entity-ring-builder.js
</a>
<a class="source" href="../modules/london-crime-graphic.html">
./demo/modules/london-crime-graphic.js
</a>
<a class="source" href="../modules/london-crime-lines.html">
./demo/modules/london-crime-lines.js
</a>
<a class="source" href="../modules/london-crime-stacked-bars.html">
./demo/modules/london-crime-stacked-bars.js
</a>
<a class="source" href="../modules/lottie-loader.html">
./demo/modules/lottie-loader.js
</a>
<a class="source" href="../modules/simple-chart-frame-tests.html">
./demo/modules/simple-chart-frame-tests.js
</a>
<a class="source" href="../modules/simple-chart-frame.html">
./demo/modules/simple-chart-frame.js
</a>
<a class="source" href="../modules/simple-graph-lines.html">
./demo/modules/simple-graph-lines.js
</a>
<a class="source" href="../modules/simple-graph-stacked-bars.html">
./demo/modules/simple-graph-stacked-bars.js
</a>
<a class="source" href="../modules/wikipedia-views-spiral-chart.html">
./demo/modules/wikipedia-views-spiral-chart.js
</a>
<a class="source" href="animated-highlight-gradient-text-snippet.html">
./demo/snippets/animated-highlight-gradient-text-snippet.js
</a>
<a class="source" href="animated-hover-gradient-snippet.html">
./demo/snippets/animated-hover-gradient-snippet.js
</a>
<a class="source" href="animated-word-gradient-snippet.html">
./demo/snippets/animated-word-gradient-snippet.js
</a>
<a class="source" href="before-after-slider-infographic.html">
./demo/snippets/before-after-slider-infographic.js
</a>
<a class="source" href="bubbles-text-snippet.html">
./demo/snippets/bubbles-text-snippet.js
</a>
<a class="source" href="green-box-snippet.html">
./demo/snippets/green-box-snippet.js
</a>
<a class="source" href="jazzy-button-snippet.html">
./demo/snippets/jazzy-button-snippet.js
</a>
<a class="source" href="page-performance-snippet-test.html">
./demo/snippets/page-performance-snippet-test.js
</a>
<a class="source" href="page-performance-snippet.html">
./demo/snippets/page-performance-snippet.js
</a>
<a class="source" href="pan-image-snippet.html">
./demo/snippets/pan-image-snippet.js
</a>
<a class="source" href="placeholder-effect-snippet.html">
./demo/snippets/placeholder-effect-snippet.js
</a>
<a class="source" href="ripple-effect-snippet.html">
./demo/snippets/ripple-effect-snippet.js
</a>
<a class="source" href="risograph-text-gradient-snippet.html">
./demo/snippets/risograph-text-gradient-snippet.js
</a>
<a class="source" href="spotlight-text-snippet-test.html">
./demo/snippets/spotlight-text-snippet-test.js
</a>
<a class="source" href="spotlight-text-snippet.html">
./demo/snippets/spotlight-text-snippet.js
</a>
<a class="source" href="swirling-stripes-text-snippet.html">
./demo/snippets/swirling-stripes-text-snippet.js
</a>
<a class="source" href="text-snippet-helper.html">
./demo/snippets/text-snippet-helper.js
</a>
<a class="source" href="word-highlighter-snippet.html">
./demo/snippets/word-highlighter-snippet.js
</a>
<a class="source" href="worley-text-gradient-snippet.html">
./demo/snippets/worley-text-gradient-snippet.js
</a>
</div>
</div>
</li>
</ul>
<ul class="sections">
<li id="section-1">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-1">§</a>
</div>
<h1 id="demo-snippets-004">Demo Snippets 004</h1>
<p>Snippets included in the Scrawl-canvas demo/snippets folder</p>
<p>Related files:</p>
<ul>
<li><a href="../snippets-004.html">Snippets included in the Scrawl-canvas demo/snippets folder</a></li>
<li><a href="./animated-hover-gradient-snippet.html">Animated hover gradient snippet</a></li>
<li><a href="./animated-word-gradient-snippet.html">Animated word gradient snippet</a></li>
<li><a href="./green-box-snippet.html">Green box snippet</a></li>
<li><a href="./jazzy-button-snippet.html">Jazzy button snippet</a></li>
<li><a href="./page-performance-snippet.html">Page performance snippet</a></li>
<li><a href="./pan-image-snippet.html">Pan image snippet</a></li>
<li><a href="./placeholder-effect-snippet.html">Placeholder effect snippet</a></li>
<li><a href="./ripple-effect-snippet.html">Ripple effect snippet</a></li>
<li><a href="./spotlight-text-snippet.html">Spotlight text snippet</a></li>
<li><a href="./word-highlighter-snippet.html">Word highlighter snippet</a></li>
</ul>
</div>
</li>
<li id="section-2">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-2">§</a>
</div>
<h3 id="pan-image-snippet">‘Pan image’ snippet</h3>
<p><strong>Purpose:</strong> Displays a pan effect on an image, where users can click and drag the image to explore it</p>
<p><strong>Function input:</strong> </p>
<ul>
<li>the DOM element - a block element - usually a <div> element - containing one or more <img> elements</li>
</ul>
<p><strong>Function output:</strong> a Javascript object will be returned, containing the following attributes</p>
<pre><code>{
element <span class="hljs-comment">// the Scrawl-canvas wrapper for the DOM element supplied to the function</span>
canvas <span class="hljs-comment">// the Scrawl-canvas wrapper for the snippet's canvas</span>
animation <span class="hljs-comment">// the Scrawl-canvas animation object</span>
demolish <span class="hljs-comment">// remove the snippet from the Scrawl-canvas library</span>
}
</code></pre>
<h5 id="usage-example">Usage example:</h5>
<pre><code><span class="hljs-keyword">import</span> panImage <span class="hljs-keyword">from</span> <span class="hljs-string">'./relative/or/absolute/path/to/this/file.js'</span>;
<span class="hljs-keyword">let</span> myElements = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'.some-class'</span>);
myElements.<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">el</span> =></span> <span class="hljs-title function_">panImage</span>(el));
</code></pre>
</div>
</li>
<li id="section-3">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-3">§</a>
</div>
<p>Import the Scrawl-canvas object </p>
<ul>
<li>there’s various ways to do this. See <a href="../dom-001.html">Demo DOM-001</a> for more details</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> scrawl <span class="hljs-keyword">from</span> <span class="hljs-string">'../../source/scrawl.js'</span>;</pre></div></div>
</li>
<li id="section-4">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-4">§</a>
</div>
<p><strong>Effects on the element:</strong> </p>
<ul>
<li>Sets the element background to <code>transparent</code></li>
<li>Imports any <img> elements it finds in the element, switching their display styling to ‘none’</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) {</pre></div></div>
</li>
<li id="section-5">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-5">§</a>
</div>
<p>Apply the snippet to the DOM element</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> snippet = scrawl.<span class="hljs-title function_">makeSnippet</span>({
<span class="hljs-attr">domElement</span>: el,
});
<span class="hljs-keyword">if</span> (snippet) {</pre></div></div>
</li>
<li id="section-6">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-6">§</a>
</div>
<p>Set some convenience variables</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> canvas = snippet.<span class="hljs-property">canvas</span>,
animation = snippet.<span class="hljs-property">animation</span>,
group = canvas.<span class="hljs-property">base</span>.<span class="hljs-property">name</span>,
name = snippet.<span class="hljs-property">element</span>.<span class="hljs-property">name</span>;</pre></div></div>
</li>
<li id="section-7">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-7">§</a>
</div>
<p>Set the DOM element’s background color to transparent so we can see the new canvas</p>
</div>
<div class="content"><div class='highlight'><pre> el.<span class="hljs-property">style</span>.<span class="hljs-property">backgroundColor</span> = <span class="hljs-string">'transparent'</span>;</pre></div></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-8">§</a>
</div>
<p>Grab all the child <img> elements </p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> images = el.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">'img'</span>),
imgName = <span class="hljs-string">`<span class="hljs-subst">${name}</span>-image`</span>;</pre></div></div>
</li>
<li id="section-9">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-9">§</a>
</div>
<p>If the coder gave the DOM element a sane id attribute value then all our names will be sensible names. If not, then Scrawl-canvas will have computer-generated an id for the element. These generated names often include characters that do not sit well with the CSS/JS querySelector string requirements. So we have to make the name safe to be used as a search string</p>
</div>
<div class="content"><div class='highlight'><pre> imgName = imgName.<span class="hljs-title function_">replace</span>(<span class="hljs-string">'.'</span>, <span class="hljs-string">''</span>);</pre></div></div>
</li>
<li id="section-10">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-10">§</a>
</div>
<p>Update all the <img> elements we found. In particular:</p>
<ul>
<li>add the name to the element’s class</li>
<li>set the indexed name as the element’s id value</li>
<li>set the element’s display styling attrinute to ‘none’ - we don’t weant it displaying in the DOM, we need it to display in the new canvas</li>
</ul>
</div>
<div class="content"><div class='highlight'><pre> images.<span class="hljs-title function_">forEach</span>(<span class="hljs-function">(<span class="hljs-params">img, index</span>) =></span> {
<span class="hljs-keyword">let</span> classes = img.<span class="hljs-title function_">getAttribute</span>(<span class="hljs-string">'class'</span>)
<span class="hljs-keyword">if</span> (!classes) classes = <span class="hljs-string">''</span>;
classes += <span class="hljs-string">` <span class="hljs-subst">${imgName}</span>`</span>;
img.<span class="hljs-title function_">setAttribute</span>(<span class="hljs-string">'class'</span>, classes);
img.<span class="hljs-property">id</span> = <span class="hljs-string">`<span class="hljs-subst">${imgName}</span>-<span class="hljs-subst">${index}</span>`</span>;
img.<span class="hljs-property">style</span>.<span class="hljs-property">display</span> = <span class="hljs-string">'none'</span>;
});</pre></div></div>
</li>
<li id="section-11">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-11">§</a>
</div>
<p>Import all the images we found into Scrawl-canvas</p>
</div>
<div class="content"><div class='highlight'><pre> scrawl.<span class="hljs-title function_">importDomImage</span>(<span class="hljs-string">`.<span class="hljs-subst">${imgName}</span>`</span>);</pre></div></div>
</li>
<li id="section-12">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-12">§</a>
</div>
<p>Configuration - coders can set ‘data-x’ and ‘data-y’ attributes on the DOM element to indicate which area of the image should be displayed in the new canvas when the page first loads</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> copyStartX = el.<span class="hljs-property">dataset</span>.<span class="hljs-property">x</span> || <span class="hljs-number">0</span>,
copyStartY = el.<span class="hljs-property">dataset</span>.<span class="hljs-property">y</span> || <span class="hljs-number">0</span>;</pre></div></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-13">§</a>
</div>
<p>We will display the first image we found in a Picture entity</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> [w, h] = canvas.<span class="hljs-title function_">get</span>(<span class="hljs-string">'dimensions'</span>);
<span class="hljs-keyword">const</span> asset = scrawl.<span class="hljs-property">library</span>.<span class="hljs-property">asset</span>[<span class="hljs-string">`<span class="hljs-subst">${imgName}</span>-0`</span>];
<span class="hljs-keyword">const</span> panImage = scrawl.<span class="hljs-title function_">makePicture</span>({
<span class="hljs-attr">name</span>: <span class="hljs-string">`<span class="hljs-subst">${imgName}</span>-panimage`</span>,
group,
asset,
<span class="hljs-attr">width</span>: w,
<span class="hljs-attr">height</span>: h,
<span class="hljs-attr">copyWidth</span>: w,
<span class="hljs-attr">copyHeight</span>: h,
copyStartX,
copyStartY,
});
<span class="hljs-keyword">let</span> cursor = <span class="hljs-string">'grab'</span>,
lastX = <span class="hljs-number">0</span>,
lastY = <span class="hljs-number">0</span>,
aspectWidth = <span class="hljs-number">1</span>,
aspectHeight = <span class="hljs-number">1</span>;</pre></div></div>
</li>
<li id="section-14">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-14">§</a>
</div>
<p>The pan effect, where the user can click and drag the image within its container to explore large images in small areas. To achieve the effect we split the functionality across three separate event listeners, which capture the three key actions associated with the effect: starting a drag; continuing a drag; and ending a drag.</p>
</div>
<div class="content"><div class='highlight'><pre> scrawl.<span class="hljs-title function_">addListener</span>(<span class="hljs-string">'down'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =></span> {
<span class="hljs-keyword">let</span> here = canvas.<span class="hljs-property">here</span>;
<span class="hljs-keyword">if</span> (here.<span class="hljs-property">active</span> && <span class="hljs-string">'grab'</span> === cursor) {
cursor = <span class="hljs-string">'grabbing'</span>;
el.<span class="hljs-property">style</span>.<span class="hljs-property">cursor</span> = cursor;
<span class="hljs-keyword">let</span> {x, y} = here;</pre></div></div>
</li>
<li id="section-15">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-15">§</a>
</div>
<p>@ts-expect-error</p>
</div>
<div class="content"><div class='highlight'><pre> lastX = x;</pre></div></div>
</li>
<li id="section-16">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-16">§</a>
</div>
<p>@ts-expect-error</p>
</div>
<div class="content"><div class='highlight'><pre> lastY = y;
}
}, el);
scrawl.<span class="hljs-title function_">addListener</span>(<span class="hljs-string">'move'</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =></span> {
<span class="hljs-keyword">if</span> (<span class="hljs-string">'grabbing'</span> === cursor) {
<span class="hljs-keyword">let</span> {x, y} = canvas.<span class="hljs-property">here</span>;</pre></div></div>
</li>
<li id="section-17">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-17">§</a>
</div>
<p>@ts-expect-error</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> dx = lastX - x,</pre></div></div>
</li>
<li id="section-18">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-18">§</a>
</div>
<p>@ts-expect-error</p>
</div>
<div class="content"><div class='highlight'><pre> dy = lastY - y;
panImage.<span class="hljs-title function_">setDelta</span>({
<span class="hljs-attr">copyStartX</span>: dx * aspectWidth,
<span class="hljs-attr">copyStartY</span>: dy * aspectHeight,
});</pre></div></div>
</li>
<li id="section-19">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-19">§</a>
</div>
<p>@ts-expect-error</p>
</div>
<div class="content"><div class='highlight'><pre> lastX = x;</pre></div></div>
</li>
<li id="section-20">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-20">§</a>
</div>
<p>@ts-expect-error</p>
</div>
<div class="content"><div class='highlight'><pre> lastY = y;
}
}, el);
scrawl.<span class="hljs-title function_">addListener</span>([<span class="hljs-string">'up'</span>, <span class="hljs-string">'leave'</span>], <span class="hljs-function">(<span class="hljs-params">e</span>) =></span> {
<span class="hljs-keyword">if</span> (<span class="hljs-string">'grabbing'</span> === cursor) {
cursor = <span class="hljs-string">'grab'</span>;
el.<span class="hljs-property">style</span>.<span class="hljs-property">cursor</span> = cursor;
<span class="hljs-keyword">let</span> {x, y} = canvas.<span class="hljs-property">here</span>;</pre></div></div>
</li>
<li id="section-21">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-21">§</a>
</div>
<p>@ts-expect-error</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> dx = lastX - x,</pre></div></div>
</li>
<li id="section-22">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-22">§</a>
</div>
<p>@ts-expect-error</p>
</div>
<div class="content"><div class='highlight'><pre> dy = lastY - y;
panImage.<span class="hljs-title function_">setDelta</span>({
<span class="hljs-attr">copyStartX</span>: dx * aspectWidth,
<span class="hljs-attr">copyStartY</span>: dy * aspectHeight,
});
lastX = <span class="hljs-number">0</span>;
lastY = <span class="hljs-number">0</span>;
}
}, el);</pre></div></div>
</li>
<li id="section-23">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-23">§</a>
</div>
<p>We’re checking dimensions here partly because images load asynchronously and during the early part of that process their <img> elements will supply incorrect information to the script which is trying to set up the canvas element which will (eventually) host their image data. But we also need to check because the script has no way of knowing what sort of image it is dealing with - for instance an <img> element with a “srcset” attribute will load new images if the user decides to expand their browser’s window - which would have an impact on the assumptions we make in our scaling and dragging calculations.</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">const</span> checkDimensions = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {
<span class="hljs-keyword">let</span> [canvasWidth, canvasHeight] = canvas.<span class="hljs-title function_">get</span>(<span class="hljs-string">'dimensions'</span>);
<span class="hljs-keyword">let</span> [imageWidth, imageHeight] = panImage.<span class="hljs-title function_">get</span>(<span class="hljs-string">'dimensions'</span>);</pre></div></div>
</li>
<li id="section-24">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-24">§</a>
</div>
<p>check to see if there’s been any resize browser resize or CSS layout change that affects our DOM element</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> (canvasWidth !== imageWidth || canvasHeight !== imageHeight) {
<span class="hljs-keyword">let</span> [sourceWidth, sourceHeight] = panImage.<span class="hljs-title function_">get</span>(<span class="hljs-string">'sourceDimensions'</span>);</pre></div></div>
</li>
<li id="section-25">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-25">§</a>
</div>
<p>We want the image we paint in our canvas to keep its asset’s original aspect ratio</p>
</div>
<div class="content"><div class='highlight'><pre> aspectWidth = canvasWidth / sourceWidth;
aspectHeight = canvasHeight / sourceHeight;</pre></div></div>
</li>
<li id="section-26">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-26">§</a>
</div>
<p>We want the zoom level to be x3 (along the width) with respect to the DOM element’s dimensions</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">let</span> setToHalfWidth = <span class="hljs-number">50</span> / (aspectWidth * <span class="hljs-number">100</span>);
<span class="hljs-keyword">let</span> ratioWidth = aspectWidth * setToHalfWidth * <span class="hljs-number">100</span>,
ratioHeight = aspectHeight * setToHalfWidth * <span class="hljs-number">100</span>;
panImage.<span class="hljs-title function_">set</span>({
<span class="hljs-attr">width</span>: canvasWidth,
<span class="hljs-attr">height</span>: canvasHeight,
<span class="hljs-attr">copyWidth</span>: ratioWidth + <span class="hljs-string">'%'</span>,
<span class="hljs-attr">copyHeight</span>: ratioHeight + <span class="hljs-string">'%'</span>,
});
}
};</pre></div></div>
</li>
<li id="section-27">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-27">§</a>
</div>
<p>Invoke our ‘checkDimensions’ function at the start of every Display cycle</p>
</div>
<div class="content"><div class='highlight'><pre> animation.<span class="hljs-title function_">set</span>({
<span class="hljs-attr">commence</span>: checkDimensions,
});
}</pre></div></div>
</li>
<li id="section-28">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-28">§</a>
</div>
<p>Return the snippet, so coders can access the snippet’s parts - in case they need to tweak the output to meet the web page’s specific requirements</p>
</div>
<div class="content"><div class='highlight'><pre> <span class="hljs-keyword">return</span> snippet;
};</pre></div></div>
</li>
</ul>
</div>
</body>
</html>