Introduce minimap to style guide.

This commit is contained in:
Neil Fraser
2017-10-24 11:48:07 -07:00
committed by Neil Fraser
parent e100c66659
commit 8779a8c3d9
4 changed files with 171 additions and 164 deletions

View File

@@ -177,13 +177,13 @@ Blockly.Variables.flyoutCategoryBlocks = function(workspace) {
}; };
/** /**
* Return a new variable name that is not yet being used. This will try to * Return a new variable name that is not yet being used. This will try to
* generate single letter variable names in the range 'i' to 'z' to start with. * generate single letter variable names in the range 'i' to 'z' to start with.
* If no unique name is located it will try 'i' to 'z', 'a' to 'h', * If no unique name is located it will try 'i' to 'z', 'a' to 'h',
* then 'i2' to 'z2' etc. Skip 'l'. * then 'i2' to 'z2' etc. Skip 'l'.
* @param {!Blockly.Workspace} workspace The workspace to be unique in. * @param {!Blockly.Workspace} workspace The workspace to be unique in.
* @return {string} New variable name. * @return {string} New variable name.
*/ */
Blockly.Variables.generateUniqueName = function(workspace) { Blockly.Variables.generateUniqueName = function(workspace) {
var variableList = workspace.getAllVariables(); var variableList = workspace.getAllVariables();
var newName = ''; var newName = '';

View File

@@ -37,9 +37,9 @@ goog.require('goog.dom.xml');
/** /**
* Block Exporter Tools Class * Block Exporter Tools Class
* @constructor * @constructor
*/ */
BlockExporterTools = function() { BlockExporterTools = function() {
// Create container for hidden workspace. // Create container for hidden workspace.
this.container = goog.dom.createDom('div', { this.container = goog.dom.createDom('div', {

View File

@@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Blockly Demo: Minimap </title> <title>Blockly Demo: Minimap</title>
<script src="../../blockly_compressed.js"></script> <script src="../../blockly_compressed.js"></script>
<script src="../../blocks_compressed.js"></script> <script src="../../blocks_compressed.js"></script>
<script src="../../msg/js/en.js"></script> <script src="../../msg/js/en.js"></script>
@@ -49,41 +49,40 @@
</xml> </xml>
<script> <script>
// Inject master workspace.
var masterWorkspace = Blockly.inject('masterDiv', {
media: '../../media/',
scrollbars: true,
toolbox: document.getElementById('toolbox')
});
// Inject master workspace. // Inject workspace for minimap.
var masterWorkspace = Blockly.inject('masterDiv',{ var minimapWorkspace = Blockly.inject('mapDiv', {
media: '../../media/', media: '../../media/',
scrollbars: true, readOnly: true,
toolbox: document.getElementById('toolbox') zoom: {
}); controls: false,
wheel: true,
// Inject workspace for minimap. startScale: 0.1, // Change this according to your needs.
var minimapWorkspace = Blockly.inject('mapDiv', maxScale: 0.1,
{media: '../../media/', minScale: 0.01
readOnly: true, }
zoom: });
{controls: false,
wheel: true,
startScale: 0.1, //you can change this accorting to your needs.
maxScale: 0.1,
minScale: 0.01
}});
// Initilizing the minimap.
Minimap.init(masterWorkspace,minimapWorkspace);
// Initialize the minimap.
Minimap.init(masterWorkspace,minimapWorkspace);
</script> </script>
<style> <style>
.minimap{ .minimap{
position:absolute; position: absolute;
} }
.mapDragger{ .mapDragger{
cursor: move; cursor: move;
fill:rgb(0,0,255); fill: rgb(0,0,255);
stroke-width:0.5; stroke-width: .5;
stroke:rgb(0,0,0); stroke: rgb(0,0,0);
fill-opacity:0.1; fill-opacity: .1;
} }
</style> </style>
</body> </body>

View File

@@ -1,46 +1,46 @@
/** /**
* Blockly Demos: Code * Blockly Demos: Minimap
* *
* Copyright 2017 Google Inc. * Copyright 2017 Google Inc.
* https://developers.google.com/blockly/ * https://developers.google.com/blockly/
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/** /**
* @fileoverview JavaScript for Blockly's Minimap demo. * @fileoverview JavaScript for Blockly's Minimap demo.
* @author karnpurohit@gmail.com (Karan Purohit) * @author karnpurohit@gmail.com (Karan Purohit)
*/ */
'use strict'; 'use strict';
/** /**
* Creating a seperate namespace for minimap. * Creating a separate namespace for minimap.
*/ */
var Minimap = {}; var Minimap = {};
/** /**
* Initilize the workspace and minimap. * Initialize the workspace and minimap.
* @param {Workspace} workspace The main workspace of the user. * @param {!Workspace} workspace The main workspace of the user.
* @param {Workspace} minimap The workspace that will be used as a minimap. * @param {!Workspace} minimap The workspace that will be used as a minimap.
*/ */
Minimap.init = function(workspace, minimap){ Minimap.init = function(workspace, minimap) {
this.workspace = workspace; this.workspace = workspace;
this.minimap = minimap; this.minimap = minimap;
//Adding scroll callback functionlity to vScroll and hScroll just for this demo. // Adding scroll callback functionality to vScroll and hScroll just for this demo.
//IMPORTANT: This should be changed when there is proper UI event handling // IMPORTANT: This should be changed when there is proper UI event handling
// api available and should be handled by workspace's event listeners. // API available and should be handled by workspace's event listeners.
this.workspace.scrollbar.vScroll.setHandlePosition = function(newPosition){ this.workspace.scrollbar.vScroll.setHandlePosition = function(newPosition) {
this.handlePosition_ = newPosition; this.handlePosition_ = newPosition;
this.svgHandle_.setAttribute(this.positionAttribute_, this.handlePosition_); this.svgHandle_.setAttribute(this.positionAttribute_, this.handlePosition_);
@@ -55,7 +55,7 @@ Minimap.init = function(workspace, minimap){
}; };
// Adding call back for horizontal scroll. // Adding call back for horizontal scroll.
this.workspace.scrollbar.hScroll.setHandlePosition = function(newPosition){ this.workspace.scrollbar.hScroll.setHandlePosition = function(newPosition) {
this.handlePosition_ = newPosition; this.handlePosition_ = newPosition;
this.svgHandle_.setAttribute(this.positionAttribute_, this.handlePosition_); this.svgHandle_.setAttribute(this.positionAttribute_, this.handlePosition_);
@@ -71,7 +71,7 @@ Minimap.init = function(workspace, minimap){
// Required to stop a positive feedback loop when user clicks minimap // Required to stop a positive feedback loop when user clicks minimap
// and the scroll changes, which inturn may change minimap. // and the scroll changes, which in turn may change minimap.
this.disableScrollChange = false; this.disableScrollChange = false;
// Listen to events on the main workspace. // Listen to events on the main workspace.
@@ -95,9 +95,9 @@ Minimap.init = function(workspace, minimap){
// Creating a rectangle in the minimap that represents current view. // Creating a rectangle in the minimap that represents current view.
Blockly.utils.createSvgElement('rect', { Blockly.utils.createSvgElement('rect', {
'width':100, 'width': 100,
'height':100, 'height': 100,
'class':'mapDragger' 'class': 'mapDragger'
}, this.svg); }, this.svg);
// Rectangle in the minimap that represents current view. // Rectangle in the minimap that represents current view.
@@ -105,7 +105,7 @@ Minimap.init = function(workspace, minimap){
// Adding mouse events to the rectangle, to make it Draggable. // Adding mouse events to the rectangle, to make it Draggable.
// Using Blockly.bindEvent_ to attach mouse/touch listeners. // Using Blockly.bindEvent_ to attach mouse/touch listeners.
Blockly.bindEvent_(this.mapDragger, "mousedown", null, Minimap.mousedown); Blockly.bindEvent_(this.mapDragger, 'mousedown', null, Minimap.mousedown);
//When the window change, we need to resize the minimap window. //When the window change, we need to resize the minimap window.
window.addEventListener('resize', Minimap.repositionMinimap); window.addEventListener('resize', Minimap.repositionMinimap);
@@ -113,20 +113,22 @@ Minimap.init = function(workspace, minimap){
// Mouse up event for the minimap. // Mouse up event for the minimap.
this.svg.addEventListener('mouseup', Minimap.updateMapDragger); this.svg.addEventListener('mouseup', Minimap.updateMapDragger);
//Boolen to check whether I am dragging the surface or not. //Boolean to check whether I am dragging the surface or not.
this.isDragging = false; this.isDragging = false;
}; };
Minimap.mousedown = function(e){ Minimap.mousedown = function(e) {
// Using Blockly.bindEvent_ to attach mouse/touch listeners. // Using Blockly.bindEvent_ to attach mouse/touch listeners.
Minimap.mouseMoveBindData = Blockly.bindEvent_(document,"mousemove", null, Minimap.mousemove); Minimap.mouseMoveBindData =
Minimap.mouseUpBindData = Blockly.bindEvent_(document,"mouseup", null, Minimap.mouseup); Blockly.bindEvent_(document, 'mousemove', null, Minimap.mousemove);
Minimap.mouseUpBindData =
Blockly.bindEvent_(document, 'mouseup', null, Minimap.mouseup);
Minimap.isDragging=true; Minimap.isDragging = true;
e.stopPropagation(); e.stopPropagation();
}; };
Minimap.mouseup = function(e){ Minimap.mouseup = function(e) {
Minimap.isDragging = false; Minimap.isDragging = false;
// Removing listeners. // Removing listeners.
Blockly.unbindEvent_(Minimap.mouseUpBindData); Blockly.unbindEvent_(Minimap.mouseUpBindData);
@@ -135,18 +137,18 @@ Minimap.mouseup = function(e){
e.stopPropagation(); e.stopPropagation();
}; };
Minimap.mousemove = function(e){ Minimap.mousemove = function(e) {
if(Minimap.isDragging){ if (Minimap.isDragging) {
Minimap.updateMapDragger(e); Minimap.updateMapDragger(e);
e.stopPropagation(); e.stopPropagation();
} }
}; };
/** /**
* Initilize the workspace and minimap. * Run non-UI events from the main workspace on the minimap.
* @param {Event} event Event that triggered in the main workspace. * @param {!Event} event Event that triggered in the main workspace.
*/ */
Minimap.mirrorEvent = function(event){ Minimap.mirrorEvent = function(event) {
if (event.type == Blockly.Events.UI) { if (event.type == Blockly.Events.UI) {
return; // Don't mirror UI events. return; // Don't mirror UI events.
} }
@@ -161,146 +163,152 @@ Minimap.mirrorEvent = function(event){
}; };
/** /**
* Called when window is resized. Repositions the minimap overlay. * Called when window is resized. Repositions the minimap overlay.
*/ */
Minimap.repositionMinimap = function(){ Minimap.repositionMinimap = function() {
Minimap.rect = document.getElementById('mapDiv').getBoundingClientRect(); Minimap.rect = document.getElementById('mapDiv').getBoundingClientRect();
Minimap.svg.style.top = Minimap.rect.top + 'px'; Minimap.svg.style.top = Minimap.rect.top + 'px';
Minimap.svg.style.left = Minimap.rect.left + 'px'; Minimap.svg.style.left = Minimap.rect.left + 'px';
}; };
/** /**
* Updates the rectangle's height . * Updates the rectangle's height.
*/ */
Minimap.setDraggerHeight = function(){ Minimap.setDraggerHeight = function() {
var workspaceMetrics = Minimap.workspace.getMetrics(); var workspaceMetrics = Minimap.workspace.getMetrics();
var draggerHeight = (workspaceMetrics.viewHeight / Minimap.workspace.scale) * Minimap.minimap.scale; var draggerHeight = (workspaceMetrics.viewHeight / Minimap.workspace.scale) *
Minimap.minimap.scale;
// It's zero when first block is placed. // It's zero when first block is placed.
if(draggerHeight == 0){ if (draggerHeight == 0) {
return; return;
} }
Minimap.mapDragger.setAttribute("height", draggerHeight); Minimap.mapDragger.setAttribute('height', draggerHeight);
}; };
/** /**
* Updates the rectangle's width. * Updates the rectangle's width.
*/ */
Minimap.setDraggerWidth = function(){ Minimap.setDraggerWidth = function() {
var workspaceMetrics = Minimap.workspace.getMetrics(); var workspaceMetrics = Minimap.workspace.getMetrics();
var draggerWidth = (workspaceMetrics.viewWidth / Minimap.workspace.scale) * Minimap.minimap.scale; var draggerWidth = (workspaceMetrics.viewWidth / Minimap.workspace.scale) *
Minimap.minimap.scale;
// It's zero when first block is placed. // It's zero when first block is placed.
if(draggerWidth == 0){ if (draggerWidth == 0) {
return; return;
} }
Minimap.mapDragger.setAttribute("width", draggerWidth); Minimap.mapDragger.setAttribute('width', draggerWidth);
}; };
/** /**
* Updates the overall position of the viewport of the minimap by appropriately * Updates the overall position of the viewport of the minimap by appropriately
* using translate functions. * using translate functions.
*/ */
Minimap.scaleMinimap = function(){ Minimap.scaleMinimap = function() {
var minimapBoundingBox = Minimap.minimap.getBlocksBoundingBox(); var minimapBoundingBox = Minimap.minimap.getBlocksBoundingBox();
var workspaceBoundingBox = Minimap.workspace.getBlocksBoundingBox(); var workspaceBoundingBox = Minimap.workspace.getBlocksBoundingBox();
var workspaceMetrics = Minimap.workspace.getMetrics(); var workspaceMetrics = Minimap.workspace.getMetrics();
var minimapMetrics = Minimap.minimap.getMetrics(); var minimapMetrics = Minimap.minimap.getMetrics();
//Scaling the mimimap such that all the blocks can be seen in the viewport. // Scaling the mimimap such that all the blocks can be seen in the viewport.
//This padding is default because this is how to scrollbar(in main workspace) is implemented. // This padding is default because this is how to scrollbar(in main workspace)
var topPadding = (workspaceMetrics.viewHeight) * Minimap.minimap.scale / (2 * Minimap.workspace.scale); // is implemented.
var sidePadding = (workspaceMetrics.viewWidth) * Minimap.minimap.scale / (2 * Minimap.workspace.scale); var topPadding = (workspaceMetrics.viewHeight) * Minimap.minimap.scale /
(2 * Minimap.workspace.scale);
var sidePadding = (workspaceMetrics.viewWidth) * Minimap.minimap.scale /
(2 * Minimap.workspace.scale);
// If actual padding is more than half view ports height, change it to actual padding. // If actual padding is more than half view ports height,
if((workspaceBoundingBox.y * Minimap.workspace.scale - workspaceMetrics.contentTop) // change it to actual padding.
* Minimap.minimap.scale / Minimap.workspace.scale > topPadding){ if ((workspaceBoundingBox.y * Minimap.workspace.scale -
topPadding = (workspaceBoundingBox.y * Minimap.workspace.scale - workspaceMetrics.contentTop) workspaceMetrics.contentTop) *
* Minimap.minimap.scale / Minimap.workspace.scale; Minimap.minimap.scale / Minimap.workspace.scale > topPadding) {
topPadding = (workspaceBoundingBox.y * Minimap.workspace.scale -
workspaceMetrics.contentTop) *
Minimap.minimap.scale / Minimap.workspace.scale;
} }
// If actual padding is more than half view ports height, change it to actual padding. // If actual padding is more than half view ports height,
if((workspaceBoundingBox.x * Minimap.workspace.scale - workspaceMetrics.contentLeft) // change it to actual padding.
* Minimap.minimap.scale / Minimap.workspace.scale > sidePadding){ if ((workspaceBoundingBox.x * Minimap.workspace.scale -
sidePadding = (workspaceBoundingBox.x * Minimap.workspace.scale - workspaceMetrics.contentLeft) workspaceMetrics.contentLeft) *
* Minimap.minimap.scale / Minimap.workspace.scale; Minimap.minimap.scale / Minimap.workspace.scale > sidePadding) {
sidePadding = (workspaceBoundingBox.x * Minimap.workspace.scale -
workspaceMetrics.contentLeft) *
Minimap.minimap.scale / Minimap.workspace.scale;
} }
var scalex = (minimapMetrics.viewWidth - 2 * sidePadding) / minimapBoundingBox.width; var scalex = (minimapMetrics.viewWidth - 2 * sidePadding) /
var scaley = (minimapMetrics.viewHeight - 2 * topPadding) / minimapBoundingBox.height; minimapBoundingBox.width;
var scaley = (minimapMetrics.viewHeight - 2 * topPadding) /
minimapBoundingBox.height;
Minimap.minimap.setScale(Math.min(scalex, scaley)); Minimap.minimap.setScale(Math.min(scalex, scaley));
// Translating the minimap. // Translating the minimap.
Minimap.minimap.translate( - minimapMetrics.contentLeft * Minimap.minimap.scale + sidePadding, Minimap.minimap.translate(
- minimapMetrics.contentTop * Minimap.minimap.scale + topPadding); -minimapMetrics.contentLeft * Minimap.minimap.scale + sidePadding,
-minimapMetrics.contentTop * Minimap.minimap.scale + topPadding);
}; };
/** /**
* Handles the onclick event on the minimapBoundingBox. Changes mapDraggers position. * Handles the onclick event on the minimapBoundingBox.
* @param {Event} e Event from the mouse click. * Changes mapDraggers position.
*/ * @param {!Event} e Event from the mouse click.
Minimap.updateMapDragger = function(e){ */
Minimap.updateMapDragger = function(e) {
var y = e.clientY; var y = e.clientY;
var x = e.clientX; var x = e.clientX;
var draggerHeight = Minimap.mapDragger.getAttribute("height"); var draggerHeight = Minimap.mapDragger.getAttribute('height');
var draggerWidth = Minimap.mapDragger.getAttribute("width"); var draggerWidth = Minimap.mapDragger.getAttribute('width');
var finalY = y - Minimap.rect.top - draggerHeight / 2; var finalY = y - Minimap.rect.top - draggerHeight / 2;
var finalX = x - Minimap.rect.left - draggerWidth / 2; var finalX = x - Minimap.rect.left - draggerWidth / 2;
var maxValidY = (Minimap.workspace.getMetrics().contentHeight - Minimap.workspace.getMetrics().viewHeight) var maxValidY = (Minimap.workspace.getMetrics().contentHeight -
* Minimap.minimap.scale; Minimap.workspace.getMetrics().viewHeight) * Minimap.minimap.scale;
var maxValidX = (Minimap.workspace.getMetrics().contentWidth - Minimap.workspace.getMetrics().viewWidth) var maxValidX = (Minimap.workspace.getMetrics().contentWidth -
* Minimap.minimap.scale; Minimap.workspace.getMetrics().viewWidth) * Minimap.minimap.scale;
if(y + draggerHeight / 2 > Minimap.rect.bottom){ if (y + draggerHeight / 2 > Minimap.rect.bottom) {
finalY = Minimap.rect.bottom - Minimap.rect.top - draggerHeight; finalY = Minimap.rect.bottom - Minimap.rect.top - draggerHeight;
}else if(y < Minimap.rect.top + draggerHeight / 2){ } else if (y < Minimap.rect.top + draggerHeight / 2) {
finalY = 0; finalY = 0;
} }
if(x + draggerWidth / 2 > Minimap.rect.right){ if (x + draggerWidth / 2 > Minimap.rect.right) {
finalX = Minimap.rect.right - Minimap.rect.left - draggerWidth; finalX = Minimap.rect.right - Minimap.rect.left - draggerWidth;
}else if(x < Minimap.rect.left + draggerWidth / 2){ } else if (x < Minimap.rect.left + draggerWidth / 2) {
finalX = 0; finalX = 0;
} }
// Do not go below lower bound of scrollbar. // Do not go below lower bound of scrollbar.
if(finalY > maxValidY){ if (finalY > maxValidY) {
finalY = maxValidY; finalY = maxValidY;
} }
if (finalX > maxValidX) {
if(finalX > maxValidX){
finalX = maxValidX; finalX = maxValidX;
} }
Minimap.mapDragger.setAttribute("y", finalY); Minimap.mapDragger.setAttribute('y', finalY);
Minimap.mapDragger.setAttribute("x", finalX); Minimap.mapDragger.setAttribute('x', finalX);
// Required, otherwise creates a feedback loop. // Required, otherwise creates a feedback loop.
Minimap.disableScrollChange = true; Minimap.disableScrollChange = true;
Minimap.workspace.scrollbar.vScroll.set((finalY * Minimap.workspace.scale) / Minimap.minimap.scale); Minimap.workspace.scrollbar.vScroll.set((finalY * Minimap.workspace.scale) /
Minimap.workspace.scrollbar.hScroll.set((finalX * Minimap.workspace.scale) / Minimap.minimap.scale); Minimap.minimap.scale);
Minimap.workspace.scrollbar.hScroll.set((finalX * Minimap.workspace.scale) /
Minimap.minimap.scale);
Minimap.disableScrollChange = false; Minimap.disableScrollChange = false;
}; };
/** /**
* Handles the onclick event on the minimapBoundingBox, paramaters are passed by * Handles the onclick event on the minimapBoundingBox, parameters are passed by
* the event handler. * the event handler.
* @param {Float} position This is the absolute postion of the scrollbar. * @param {number} position This is the absolute position of the scrollbar.
* @param {boolean} horizontal Informs if the change event if for horizontal(true) * @param {boolean} horizontal Informs if the change event if for
* scrollbar or vertical(false) scrollbar. * horizontal (true) or vertical (false) scrollbar.
*/ */
Minimap.onScrollChange = function(position, horizontal){ Minimap.onScrollChange = function(position, horizontal) {
if (!Minimap.disableScrollChange) {
if(Minimap.disableScrollChange){ Minimap.mapDragger.setAttribute(horizontal ? 'x' : 'y',
return; position * Minimap.minimap.scale / Minimap.workspace.scale);
}
var newDraggerPosition = (position * Minimap.minimap.scale / Minimap.workspace.scale);
if(horizontal){
// Change the horizontal position of dragger.
Minimap.mapDragger.setAttribute("x", newDraggerPosition);
}
else{
// Change the vertical position of dragger.
Minimap.mapDragger.setAttribute("y", newDraggerPosition);
} }
}; };