我在Khan Academy's Computer Programming lessons开发了一些程序,我想在可汗学院之外运行。怎么办?
答案 0 :(得分:15)
Khan Academy使用Processing.js,一个JavaScript库,用于与<canvas>
元素进行交互。虽然Processing本身就是一种语言,但可汗学院使用JavaScript-only Processing.js code。
因此,您需要设置一个导入Processing.js的网页,设置<canvas>
,并在画布上构建Processing.js实例。最后,您需要确保您的Khan Academy代码包含范围内Processing.js实例的所有成员(我使用with
执行此操作),以及一些等同于Khan Academy's small modifications to Processing.js的mouseIsPressed
和getImage
。
这是一些一直在为我工作的样板。可能需要进一步开发才能让它适用于更复杂的例子;如果您找到不起作用的示例,请发表评论。
<!DOCTYPE html>
<html>
<head>
<title>JavaScript</title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/processing.js/1.4.8/processing.min.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var canvas = document.getElementById("canvas");
var processing = new Processing(canvas, function(processing) {
processing.size(400, 400);
processing.background(0xFFF);
var mouseIsPressed = false;
processing.mousePressed = function () { mouseIsPressed = true; };
processing.mouseReleased = function () { mouseIsPressed = false; };
var keyIsPressed = false;
processing.keyPressed = function () { keyIsPressed = true; };
processing.keyReleased = function () { keyIsPressed = false; };
function getImage(s) {
var url = "https://www.kasandbox.org/programming-images/" + s + ".png";
processing.externals.sketch.imageCache.add(url);
return processing.loadImage(url);
}
// use degrees rather than radians in rotate function
var rotateFn = processing.rotate;
processing.rotate = function (angle) {
rotateFn(processing.radians(angle));
};
with (processing) {
// INSERT YOUR KHAN ACADEMY PROGRAM HERE
}
if (typeof draw !== 'undefined') processing.draw = draw;
});
</script>
</body>
</html>
答案 1 :(得分:3)
ADDON回答罗伯特:
Processing.js使用弧度作为角度值的默认值,Khan Academy JS使用度数。如果你在上面的罗伯特代码中添加以下行(在with语句之前),那么你可以使用来自KA的rotate命令。
var rotateFn = processing.rotate;
processing.rotate = function(angle) {
rotateFn(processing.radians(angle));
}
答案 2 :(得分:0)
是的,很抱歉,我对这个问题迟到了。但是我自己解决了...
您可以克隆this repository或按照下面的说明进行操作:
或者您可以这样设置: 在您的 index.html 中,将源代码放到所有这三个文件中:
Processing.js:
loadKa.js:
这是将多个单独的文件一起加载的生产代码:
!(function(window, JSON, localStorage)
{
function createProcessing()
{
var args = Array.prototype.slice.call(arguments);
args.push({ beginCode: "with(processing)\n{", endCode: "}"});
var any = combine.apply(this, args);
this.cache = window.cache = {};
this.cache.loadedImages = window.cache.loadedImages = {};
this.cache.imageNames = window.cache.imageNames = [
"avatars/aqualine-sapling",
"avatars/aqualine-seed",
"avatars/aqualine-seedling",
"avatars/aqualine-tree",
"avatars/aqualine-ultimate",
"avatars/avatar-team",
"avatars/duskpin-sapling",
"avatars/duskpin-seed",
"avatars/duskpin-tree",
"avatars/duskpin-ultimate",
"avatars/leaf-blue",
"avatars/leaf-green",
"avatars/leaf-grey",
"avatars/leaf-orange",
"avatars/leaf-red",
"avatars/leaf-yellow",
"avatars/leafers-sapling",
"avatars/leafers-seed",
"avatars/leafers-seedling",
"avatars/leafers-tree",
"avatars/leafers-ultimate",
"avatars/marcimus",
"avatars/marcimus-orange",
"avatars/marcimus-purple",
"avatars/marcimus-red",
"avatars/mr-pants",
"avatars/mr-pants-green",
"avatars/mr-pants-orange",
"avatars/mr-pants-pink",
"avatars/mr-pants-purple",
"avatars/mr-pants-with-hat",
"avatars/mr-pink",
"avatars/mr-pink-green",
"avatars/mr-pink-orange",
"avatars/old-spice-man",
"avatars/old-spice-man-blue",
"avatars/orange-juice-squid",
"avatars/piceratops-sapling",
"avatars/piceratops-seed",
"avatars/piceratops-seedling",
"avatars/piceratops-tree",
"avatars/piceratops-ultimate",
"avatars/primosaur-sapling",
"avatars/primosaur-seed",
"avatars/primosaur-seedling",
"avatars/primosaur-tree",
"avatars/primosaur-ultimate",
"avatars/purple-pi",
"avatars/purple-pi-pink",
"avatars/purple-pi-teal",
"avatars/questionmark",
"avatars/robot_female_1",
"avatars/robot_female_2",
"avatars/robot_female_3",
"avatars/robot_male_1",
"avatars/robot_male_2",
"avatars/robot_male_3",
"avatars/spunky-sam",
"avatars/spunky-sam-green",
"avatars/spunky-sam-orange",
"avatars/spunky-sam-red",
"avatars/starky-sapling",
"avatars/starky-seed",
"avatars/starky-seedling",
"avatars/starky-tree",
"avatars/starky-ultimate",
"creatures/Hopper-Happy",
"creatures/Hopper-Cool",
"creatures/Hopper-Jumping",
"creatures/OhNoes",
"creatures/OhNoes-Happy",
"creatures/OhNoes-Hmm",
"cute/Blank",
"cute/BrownBlock",
"cute/CharacterBoy",
"cute/CharacterCatGirl",
"cute/CharacterHornGirl",
"cute/CharacterPinkGirl",
"cute/CharacterPrincessGirl",
"cute/ChestClosed",
"cute/ChestLid",
"cute/ChestOpen",
"cute/DirtBlock",
"cute/DoorTallClosed",
"cute/DoorTallOpen",
"cute/EnemyBug",
"cute/GemBlue",
"cute/GemGreen",
"cute/GemOrange",
"cute/GrassBlock",
"cute/Heart",
"cute/Key",
"cute/PlainBlock",
"cute/RampEast",
"cute/RampWest",
"cute/Rock",
"cute/RoofEast",
"cute/RoofNorth",
"cute/RoofNorthEast",
"cute/RoofNorthWest",
"cute/RoofSouth",
"cute/RoofSouthEast",
"cute/RoofSouthWest",
"cute/RoofWest",
"cute/Selector",
"cute/ShadowEast",
"cute/ShadowNorth",
"cute/ShadowNorthEast",
"cute/ShadowNorthWest",
"cute/ShadowSideWest",
"cute/ShadowSouth",
"cute/ShadowSouthEast",
"cute/ShadowSouthWest",
"cute/ShadowWest",
"cute/WoodBlock",
"cute/Star",
"cute/StoneBlock",
"cute/StoneBlockTall",
"cute/TreeShort",
"cute/TreeTall",
"space/girl2",
"space/girl3",
"space/girl4",
"space/girl5",
"space/healthheart",
"space/minus",
"space/octopus",
"space/planet",
"space/plus",
"space/rocketship",
"space/star",
"space/3",
"space/4",
"space/5",
"space/6",
"space/7",
"space/8",
"space/9"
];
window.links = {
proxyUrl : "https://cors-anywhere.herokuapp.com/",
image : ["https://www.kasandbox.org/third_party/javascript-khansrc/live-editor/build/images/",
"https://github.com/Khan/live-editor/tree/master/images",
"https://www.kasandbox.org/programming-images/"],
};
var self = this;
this.setup = function()
{
function code(processing)
{
processing.size(400, 400);
processing.background(255, 255, 255);
processing.angleMode = "degrees";
processing.mousePressed = function() {};
processing.mouseReleased = function() {};
processing.mouseMoved = function() {};
processing.mouseDragged = function() {};
processing.mouseOver = function() {};
processing.mouseOut = function() {};
processing.keyPressed = function() {};
processing.keyReleased = function() {};
processing.keyTyped = function() {};
processing.getSound = function(name)
{
return "Sound";
};
processing.playSound = function(sound)
{
console.log(sound + " is not supported yet...");
};
processing.getImage = function(name)
{
return (window.cache || self.cache).loadedImages[name] || processing.get(0, 0, 1, 1);
};
var lastGet = processing.get;
processing.get = function()
{
try{
return lastGet.apply(this, arguments);
}
catch(e)
{
if(arguments[2] !== 0 && arguments[3] !== 0)
{
console.log(e);
}else{
throw e;
}
}
};
processing.debug = function(event)
{
try{
return window.console.log.apply(this, arguments);
}
catch(e)
{
processing.println.apply(this, arguments);
}
};
processing.Program = {
restart: function()
{
window.location.reload();
},
assertEqual: function(equiv)
{
if(!equiv)
{
console.warn(equiv);
}
},
};
}
code = combine(new Function("return " + code.toString().split("\n").join(" "))(), any);
var matched = code.toString().match("this[ ]*\[[ ]*\[[ ]*(\"KAInfiniteLoopSetTimeout\")[ ]*\][ ]*\][ ]*\([ ]*\d*[ ]*\);*");
if(matched)
{
code = new Function("return " + code.toString().replace(matched[0], ""))();
}
window.canvas = document.getElementById("canvas");
window.processing = new Processing(canvas, code);
};
this.imageProcessing = new Processing(canvas, function(processing)
{
try{
processing.imageCache = JSON.parse(localStorage.getItem("imageCache"));
}
catch(e)
{
console.log(e);
}
if(!processing.imageCache)
{
processing.imageCache = {};
}
processing.getImage = function(name, callback, url)
{
if(name === undefined) { return get(0, 0, 1, 1); }
url = url || window.links.image[0] + name.split(".")[0] + ".png";
callback = callback || function() {};
if(!processing.imageCache)
{
var img = processing.loadImage(url);
callback(img, name);
return img;
}
if(processing.imageCache[name])
{
var img = processing.loadImage(processing.imageCache[name]);
callback(img, name);
return img;
}
toDataURL(window.links.proxyUrl + url, function(dataUrl)
{
processing.imageCache[name] = dataUrl;
localStorage.setItem("imageCache", JSON.stringify(processing.imageCache));
callback(processing.imageCache[name], name);
});
return processing.loadImage(processing.imageCache[url] || url);
};
window.cache.imageNames.forEach(function(element, index, array)
{
processing.getImage(element, function(img, name)
{
window.cache.loadedImages[name] = img;
if(index === array.length - 1)
{
(window.setTimeout || function(func)
{
return func.apply(this, arguments);
})
(function()
{
self.setup();
}, 50);
}
});
});
});
}
function combine(a, c)
{
var args = Array.prototype.slice.call(arguments);
var config = {};
var funcArgs = "";
var join = "";
for(var i = 0; i < args.length; i++)
{
if(typeof args[i] === "object")
{
config = args[i];
continue;
}
var to = args[i].toString();
var temp = to.substring(to.indexOf('(') + 1, to.indexOf(')'));
if(temp !== "" && temp !== " ")
{
funcArgs += temp + ",";
}
join += to.slice(to.indexOf('{') + 1, -1);
}
funcArgs = funcArgs.slice(0, -1);
return new Function("return function any(" + funcArgs + "){" + (config.beginCode || "").replace("\n", "") + join + (config.endCode || "") + "}")();
}
function toDataURL(url, callback)
{
var xhr = new XMLHttpRequest();
xhr.onload = function()
{
var reader = new FileReader();
reader.onloadend = function()
{
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
return {
createProcessing: window.createProcessing = this.createProcessing = createProcessing,
toDataURL: window.toDataURL = this.toDataURL = toDataURL,
combine: window.combine = this.combine = combine,
};
}(
(window || {}),
(JSON || { stringify: function() { return "{}"; }, parse: function() { return {}; } }),
(localStorage || { getItem: function() { return {} }, setItem: function() {}, removeItem: function() {} })
));
Index.js:
在您的 index.js 文件中 用法:
function main()
{
//Your code here (Trust me it really works!)
}
createProcessing(main);
您还可以将更多参数作为函数添加到 createProcessing 函数中。 是的,除了声音,我有时什么都有,有时候(很少)大肆宣传!