create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
331 lines (291 loc) • 19.7 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
<meta name="description" content="Let the user draw a Shape using the mouse or finger without any constraints." />
<meta itemprop="description" content="Let the user draw a Shape using the mouse or finger without any constraints." />
<meta property="og:description" content="Let the user draw a Shape using the mouse or finger without any constraints." />
<meta name="twitter:description" content="Let the user draw a Shape using the mouse or finger without any constraints." />
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="../assets/css/style.css">
<!-- Copyright 1998-2025 by Northwoods Software Corporation. -->
<meta itemprop="name" content="Freehand Drawing Tool to Draw Lines with Mouse or Finger or Stylus, Supporting Resizing, Reshaping, and Rotating" />
<meta property="og:title" content="Freehand Drawing Tool to Draw Lines with Mouse or Finger or Stylus, Supporting Resizing, Reshaping, and Rotating" />
<meta name="twitter:title" content="Freehand Drawing Tool to Draw Lines with Mouse or Finger or Stylus, Supporting Resizing, Reshaping, and Rotating" />
<meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/freehanddrawing.png" />
<meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/freehanddrawing.png" />
<meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/freehanddrawing.png" />
<meta property="og:url" content="https://gojs.net/latest/samples/FreehandDrawing.html" />
<meta property="twitter:url" content="https://gojs.net/latest/samples/FreehandDrawing.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="twitter:domain" content="gojs.net" />
<title>
Freehand Drawing Tool to Draw Lines with Mouse or Finger or Stylus, Supporting Resizing, Reshaping, and Rotating | GoJS Diagramming Library
</title>
</head>
<body>
<!-- This top nav is not part of the sample code -->
<nav id="navTop" class=" w-full h-[var(--topnav-h)] z-30 bg-white border-b border-b-gray-200">
<div class="max-w-screen-xl mx-auto flex flex-wrap items-start justify-between px-4">
<a class="text-white bg-nwoods-primary font-bold !leading-[calc(var(--topnav-h)_-_1px)] my-0 px-2 text-4xl lg:text-5xl logo"
href="../">
GoJS
</a>
<div class="relative">
<button id="topnavButton" class="h-[calc(var(--topnav-h)_-_1px)] px-2 m-0 text-gray-900 bg-inherit shadow-none md:hidden hover:!bg-inherit hover:!text-nwoods-accent hover:!shadow-none" aria-label="Navigation">
<svg class="h-7 w-7 block" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div id="topnavList" class="hidden md:block">
<div class="absolute right-0 z-30 flex flex-col items-end rounded border border-gray-200 p-4 pl-12 shadow bg-white text-gray-900 font-semibold
md:flex-row md:space-x-4 md:items-start md:border-0 md:p-0 md:shadow-none md:bg-inherit">
<a href="../learn/">Learn</a>
<a href="../samples/">Samples</a>
<a href="../intro/">Intro</a>
<a href="../api/">API</a>
<a href="../download.html">Download</a>
<a href="https://forum.nwoods.com/c/gojs/11" target="_blank" rel="noopener">Forum</a>
<a id="tc" href="https://nwoods.com/contact.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/contact.html', 'contact');">Contact</a>
<a id="tb" href="https://nwoods.com/sales/index.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/sales/index.html', 'buy');">Buy</a>
</div>
</div>
</div>
</div>
</nav>
<script>
window.addEventListener("DOMContentLoaded", function () {
// topnav
var topButton = document.getElementById("topnavButton");
var topnavList = document.getElementById("topnavList");
if (topButton && topnavList) {
topButton.addEventListener("click", function (e) {
topnavList
.classList
.toggle("hidden");
e.stopPropagation();
});
document.addEventListener("click", function (e) {
// if the clicked element isn't the list, close the list
if (!topnavList.classList.contains("hidden") && !e.target.closest("#topnavList")) {
topButton.click();
}
});
// set active <a> element
var url = window
.location
.href
.toLowerCase();
var aTags = topnavList.getElementsByTagName('a');
for (var i = 0; i < aTags.length; i++) {
var lowerhref = aTags[i]
.href
.toLowerCase();
if (lowerhref.endsWith('.html'))
lowerhref = lowerhref.slice(0, -5);
if (url.startsWith(lowerhref)) {
aTags[i]
.classList
.add('active');
break;
}
}
}
});
</script>
<div class="flex flex-col prose">
<div class="w-full max-w-screen-xl mx-auto">
<!-- * * * * * * * * * * * * * -->
<!-- Start of GoJS sample code -->
<script src="https://cdn.jsdelivr.net/npm/gojs@3.1.0"></script>
<div id="allSampleContent" class="p-4 w-full">
<script src="../extensions/FreehandDrawingTool.js"></script>
<script src="../extensions/GeometryReshapingTool.js"></script>
<script id="code">
function init() {
myDiagram = new go.Diagram('myDiagramDiv');
myDiagram.toolManager.mouseDownTools.insertAt(3, new GeometryReshapingTool());
myDiagram.nodeTemplateMap.add('FreehandDrawing',
new go.Part({
isLayoutPositioned: false,
selectionObjectName: 'SHAPE',
// custom selection adornment: a blue rectangle
selectionAdornmentTemplate:
new go.Adornment('Auto')
.add(
new go.Shape({ stroke: 'dodgerblue', fill: null }),
new go.Placeholder({ margin: -1 })
),
resizable: true,
resizeObjectName: 'SHAPE',
rotatable: true,
rotationSpot: go.Spot.Center,
reshapable: true // GeometryReshapingTool assumes nonexistent Part.reshapeObjectName would be "SHAPE"
})
.bindTwoWay('location', 'loc', go.Point.parse, go.Point.stringify)
.bindTwoWay('angle')
.add(
new go.Shape({ name: 'SHAPE', fill: null, strokeWidth: 1 })
.bindTwoWay('desiredSize', 'size', go.Size.parse, go.Size.stringify)
.bindTwoWay('geometryString', 'geo')
.bind('fill')
.bind('stroke')
.bind('strokeWidth')
)
);
// create drawing tool for myDiagram, defined in FreehandDrawingTool.js
const tool = new FreehandDrawingTool();
// provide the default JavaScript object for a new polygon in the model
tool.archetypePartData = { stroke: 'green', strokeWidth: 1, category: 'FreehandDrawing' };
// allow the tool to start on top of an existing Part
tool.isBackgroundOnly = false;
// install as first mouse-move-tool
myDiagram.toolManager.mouseMoveTools.insertAt(0, tool);
load(); // load a simple diagram from the textarea
mode(false);
}
function mode(draw) {
var tool = myDiagram.toolManager.findTool('FreehandDrawing');
tool.isEnabled = draw;
if (draw) {
document.getElementById('draw').style.filter = 'brightness(180%)';
document.getElementById('select').style.filter = '';
} else {
document.getElementById('draw').style.filter = '';
document.getElementById('select').style.filter = 'brightness(180%)';
}
}
function updateAllAdornments() {
// called after checkboxes change Diagram.allow...
myDiagram.selection.each(p => p.updateAdornments());
}
// save a model to and load a model from Json text, displayed below the Diagram
function save() {
var str = '{ "position": "' + go.Point.stringify(myDiagram.position) + '",\n "model": ' + myDiagram.model.toJson() + ' }';
document.getElementById('mySavedDiagram').value = str;
}
function load() {
var str = document.getElementById('mySavedDiagram').value;
try {
var json = JSON.parse(str);
myDiagram.initialPosition = go.Point.parse(json.position || '0 0');
myDiagram.model = go.Model.fromJson(json.model);
myDiagram.model.undoManager.isEnabled = true;
} catch (ex) {
alert(ex);
}
}
window.addEventListener('DOMContentLoaded', init);
</script>
<div id="sample">
<div id="myDiagramDiv" style="border: solid 1px black; width: 100%; height: 600px"></div>
<div id="buttons" style="user-select: none;">
<button onclick="mode(false)" id="select">Select</button>
<button onclick="mode(true)" id="draw">Draw Mode</button>
<button onclick="save()">Save</button>
<button onclick="load()">Load</button>
<label><input type="checkbox" onclick="myDiagram.allowResize = !myDiagram.allowResize; updateAllAdornments()" checked="checked" />Allow Resizing</label>
<label><input type="checkbox" onclick="myDiagram.allowReshape = !myDiagram.allowReshape; updateAllAdornments()" checked="checked" />Allow Reshaping</label>
<label><input type="checkbox" onclick="myDiagram.allowRotate = !myDiagram.allowRotate; updateAllAdornments()" checked="checked" />Allow Rotating</label>
</div>
<p>
This sample demonstrates the FreehandDrawingTool. It is defined in its own file, as <a href="../extensions/FreehandDrawingTool.js">FreehandDrawingTool.js</a>. It also
demonstrates the GeometryReshapingTool, another custom tool, defined in <a href="../extensions/GeometryReshapingTool.js">GeometryReshapingTool.js</a>.
</p>
<p>Press and drag to draw a line.</p>
<p>
Click the "Select" button to switch back to the normal selection behavior, so that you can select, resize, and rotate the shapes. The checkboxes control
whether you can resize, reshape, and/or rotate selected shapes.
</p>
<textarea id="mySavedDiagram" style="width: 100%; height: 300px">
{ "position": "0 0",
"model": { "class": "go.GraphLinksModel",
"nodeDataArray": [ {"loc":"301 143", "category":"FreehandDrawing", "geo":"M0 70 L1 70 L2 70 L3 70 L5 70 L7 70 L8 70 L11 70 L13 70 L18 69 L21 69 L25 68 L29 67 L34 67 L38 67 L42 67 L47 66 L50 66 L53 66 L55 66 L57 66 L60 66 L63 66 L64 66 L66 66 L68 66 L70 66 L72 66 L74 66 L76 66 L78 65 L81 65 L83 65 L85 65 L88 65 L90 65 L92 65 L95 65 L98 65 L100 65 L102 65 L104 65 L106 65 L109 65 L110 65 L111 65 L112 65 L113 65 L114 65 L115 65 L116 65 L118 65 L119 65 L120 65 L121 65 L122 65 L123 65 L124 65 L125 65 L126 65 L127 65 L128 65 L129 65 L131 65 L131 64 L132 64 L133 64 L134 64 L135 64 L137 64 L138 64 L139 64 L140 64 L141 64 L140 64 L139 64 L138 64 L137 64 L135 65 L134 65 L132 66 L130 67 L129 67 L126 68 L123 70 L121 71 L119 72 L116 73 L114 74 L111 76 L109 77 L106 78 L104 79 L99 81 L96 84 L94 84 L90 87 L89 87 L87 88 L86 89 L84 89 L83 90 L81 91 L80 92 L79 92 L77 93 L76 94 L74 94 L74 95 L73 96 L71 96 L70 97 L68 98 L67 98 L66 99 L64 99 L64 100 L62 100 L61 101 L60 102 L59 102 L58 103 L57 103 L57 104 L56 104 L56 105 L54 105 L54 107 L53 107 L52 108 L51 108 L51 109 L49 110 L48 111 L47 112 L47 113 L46 113 L45 114 L44 114 L44 115 L44 116 L43 116 L43 117 L42 117 L42 119 L41 119 L41 120 L40 120 L40 121 L39 122 L39 123 L38 124 L37 125 L36 126 L36 127 L35 128 L34 128 L34 129 L33 130 L33 131 L32 131 L32 130 L32 129 L33 128 L34 125 L35 122 L37 119 L39 115 L41 111 L41 106 L43 103 L45 98 L47 93 L48 90 L49 86 L51 83 L52 81 L54 78 L55 74 L55 71 L56 68 L57 65 L58 62 L58 59 L58 55 L58 53 L58 51 L58 49 L58 48 L59 45 L60 44 L60 42 L61 40 L61 38 L62 36 L64 32 L64 30 L65 29 L66 27 L66 26 L66 25 L66 24 L67 23 L67 22 L67 21 L67 20 L67 19 L68 19 L68 18 L68 17 L69 16 L69 15 L69 14 L69 12 L69 11 L69 10 L70 9 L70 8 L70 7 L70 6 L71 5 L71 4 L71 3 L71 2 L71 1 L71 0 L71 1 L71 2 L71 5 L71 6 L71 8 L71 9 L71 12 L71 14 L72 16 L72 18 L73 20 L73 23 L74 25 L74 27 L75 29 L76 32 L77 34 L78 35 L79 38 L79 39 L81 42 L81 43 L82 45 L83 46 L83 47 L83 49 L85 50 L86 52 L86 55 L86 58 L88 60 L89 62 L89 64 L90 66 L91 67 L91 69 L92 70 L92 71 L93 72 L94 73 L94 74 L94 75 L95 76 L96 77 L96 79 L97 81 L98 82 L98 83 L98 84 L99 85 L99 86 L100 87 L100 90 L101 91 L102 92 L102 93 L103 95 L103 96 L103 97 L104 98 L104 100 L104 101 L105 102 L106 103 L106 104 L107 106 L108 108 L109 110 L110 111 L111 113 L112 114 L113 115 L113 117 L115 119 L116 121 L116 123 L118 124 L119 126 L120 127 L121 129 L121 130 L122 131 L123 131 L123 132 L124 132 L124 133 L125 134 L125 135 L126 135 L127 136 L128 137 L129 138 L130 139 L131 140 L130 139 L129 138 L128 138 L126 136 L124 136 L123 134 L121 133 L118 131 L116 130 L114 128 L111 127 L107 123 L105 122 L102 120 L100 119 L98 117 L95 116 L93 114 L90 113 L88 111 L85 110 L83 108 L81 106 L78 105 L77 104 L75 103 L72 102 L71 101 L70 100 L68 99 L67 98 L65 98 L64 97 L62 96 L60 96 L58 95 L57 94 L54 93 L53 93 L51 92 L49 91 L48 91 L47 91 L45 90 L44 90 L43 89 L42 89 L41 89 L40 88 L39 87 L37 87 L36 86 L35 85 L33 85 L32 84 L31 84 L30 83 L29 83 L28 82 L26 81 L25 81 L24 80 L22 80 L21 79 L21 78 L20 78 L19 78 L18 77 L17 77 L16 76 L15 76 L15 75 L14 75 L13 75 L12 74 L11 74 L10 74 L9 74 L7 73 L5 72 L4 72 L3 72 L2 71", "key":-1} ],
"linkDataArray": [ ]
} }
</textarea>
</div>
</div>
<!-- * * * * * * * * * * * * * -->
<!-- End of GoJS sample code -->
</div>
<div id="allTagDescriptions" class="p-4 w-full max-w-screen-xl mx-auto">
<hr/>
<h3 class="text-xl">GoJS Features in this sample</h3>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Tools</h4>
<p>
<a href="../api/symbols/Tool.html" target="api">Tool</a>s handle all input events, such as mouse and keyboard interactions, in a Diagram.
There are many kinds of predefined Tool classes that implement all of the common operations that users do.
</p>
<p>
For flexibility and simplicity, all input events are canonicalized as <a href="../api/symbols/InputEvent.html" target="api">InputEvent</a>s and
redirected by the diagram to go to the <a href="../api/symbols/Diagram.html#currentTool" target="api">Diagram.currentTool</a>.
By default the Diagram.currentTool is an instance of <a href="../api/symbols/ToolManager.html" target="api">ToolManager</a> held as the <a href="../api/symbols/Diagram.html#toolManager" target="api">Diagram.toolManager</a>.
The ToolManager implements support for all mode-less tools.
The ToolManager is responsible for finding another tool that is ready to run and then making it the new current tool.
This causes the new tool to process all of the input events (mouse, keyboard, and touch) until the tool decides that it is finished,
at which time the diagram's current tool reverts back to the <a href="../api/symbols/Diagram.html#defaultTool" target="api">Diagram.defaultTool</a>, which is normally the ToolManager, again.
</p>
<p>
More information can be found in the <a href="../intro/tools.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#tools">Related samples</a>
</p>
<hr>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>GoJS Extensions</h4>
<p>
<b>GoJS</b> can be extended in a variety of ways.
The most common way to change the standard behavior is to set properties on the <a href="../api/symbols/GraphObject.html" target="api">GraphObject</a>, <a href="../api/symbols/Diagram.html" target="api">Diagram</a>, <a href="../api/symbols/CommandHandler.html" target="api">CommandHandler</a>, <a href="../api/symbols/Tool.html" target="api">Tool</a>, or <a href="../api/symbols/Layout.html" target="api">Layout</a>.
But when the desired property does not exist, you might need to override methods of CommandHandler, Tool, Layout, Link, or Node.
Methods that you can override are documented in the API reference.
Various features of GoJS can be overriden, either by replacing a method on an instance (a feature of JavaScript) or by defining a subclass.
You should not modify the prototypes of any of the <b>GoJS</b> classes.
</p>
<p>
In addition to our samples, <b>GoJS</b> provides an <strong><a href="../samples/#extensions">extensions gallery</a></strong>,
showcasing the creation of custom tools and layouts.
Those classes and samples are written in TypeScript, available at <code>../extensionsJSM/</code>,
as ECMAScript/JavaScript modules -- these use the <code>../release/go-module.js</code> library.
We recommend that you copy the files that you need into your project, so that you can adjust how they refer to the GoJS library
that you choose and so that you can include them into your own building and packaging procedures.
</p>
<p>
More information can be found in the <a href="../intro/extensions.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#extensions">Related samples</a>
</p>
<hr>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Geometry Path Strings</h4>
<p>
The <b>GoJS</b> <a href="../api/symbols/Geometry.html" target="api">Geometry</a> class controls the "shape" of a <a href="../api/symbols/Shape.html" target="api">Shape</a>,
whereas the <a href="../api/symbols/Shape.html#fill" target="api">Shape.fill</a> and <a href="../api/symbols/Shape.html#stroke" target="api">Shape.stroke</a> and other shape properties control the colors and appearance of the shape.
For common shape figures, there are predefined geometries that can be used by setting <a href="../api/symbols/Shape.html#figure" target="api">Shape.figure</a>.
However one can also define custom geometries.
</p>
<p>
One can construct any Geometry by allocating and initializing a <a href="../api/symbols/Geometry.html" target="api">Geometry</a> of at least one <a href="../api/symbols/PathFigure.html" target="api">PathFigure</a> holding some <a href="../api/symbols/PathSegment.html" target="api">PathSegment</a>s.
But you may find that using the string representation of a Geometry is easier to write and save in a database.
Use the static method <a href="../api/symbols/Geometry.html#parse" target="api">Geometry.parse</a> or the <a href="../api/symbols/Shape.html#geometryString" target="api">Shape.geometryString</a> property to transform a geometry path string into a <a href="../api/symbols/Geometry.html" target="api">Geometry</a> object.
</p>
<p>
More information can be found in the <a href="../intro/geometry.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#geometries">Related samples</a>
</p>
<hr>
</div>
</div>
</body>
<!-- This script is part of the gojs.net website, and is not needed to run the sample -->
<script src="../assets/js/goSamples.js"></script>
</html>